|
|
1.1 root 1: /*
2: * DOSCREATETHREAD example.
3: *
4: * Copyright (C) Microsoft Corp. 1986
5: *
6: * This example illustrates the use of threads and ram semaphores.
7: * Two threads are given alternating access to a shared resource, in this
8: * case, the screen. In this example a semaphore is used to protect
9: * the shared resource. See the DOSCRITSEC example for a different method.
10: *
11: * See example program "asmexmpl" for a version of this program in assembler.
12: *
13: * In general, threads in C are a little tricky, and require that the
14: * programmer be aware of the following issues:
15: *
16: * - C functions can be used as thread bodies. The function must have
17: * no arguments.
18: *
19: * - The thread function must end with a call to DOSEXIT to terminate
20: * either that thread or all threads. Simply returning, or falling
21: * off the end will lead to unpredictable results.
22: *
23: * - The C runtimes are not generally reentrant. If you call the
24: * runtime from more than one thread you need to protect it from
25: * being reentered using a semaphore.
26: *
27: *
28: * - Some of the C runtimes are built with stack checking enabled (see
29: * section 2.5 of the C run-time library reference). The stack checking
30: * depends on SS==DS. If you use these runtimes, you must allocate
31: * stack space for any threads from the default data segment and you
32: * must use the small- or medium- memory models. That way, you will
33: * have SS==DS in these threads. This is accomplished by using malloc,
34: * which maps to _nmalloc in near-data models (small- and medium- models).
35: * _nmalloc allocates memory from within the default data segment.
36: *
37: * The general solution is to use the -Aw option to tell the compiler that
38: * SS!=DS and not use the C runtimes which do stack checking (printf, etc.).
39: * Also, you must use the -Gs option to turn off stack checking in your
40: * program. For examples of the -Au option (SS!=DS and DS reloaded on
41: * function entry) see the dynlink demo.
42: *
43: *
44: * - Threads can have local variables. When accessing global data be
45: * careful about critical sections and collisions with other threads.
46: * Be especially careful of modifications to data structures which are
47: * not atomic operations. For example if you have a LONG INT in global
48: * data, and two threads access it, then you need a critical section
49: * around the code which accesses it, since the 286 is a 16 bit machine
50: * and the compiler has to generate multiple instructions to modify a
51: * long in memory. If one thread preempts another while it is half
52: * through modifying the LONG, it is left in an inconsistent state.
53: */
54:
55: #include <malloc.h>
56: #include <stdio.h>
57: #include <doscalls.h>
58: #include <subcalls.h>
59:
60: #define HELLO0 "thread zero hello\r\n"
61: #define HELLO1 "THREAD ONE HELLO\r\n"
62:
63: #define THREAD_STK_SIZE 2048 /* thread stack size */
64:
65: unsigned long sem; /* ram semaphore */
66:
67: main(argc, argv)
68: int argc;
69: char *argv[];
70: {
71: void far thread1(); /* address where thread1 gets control */
72: char far *thread1Stack; /* far pointer to thread1 stack */
73: unsigned thread1ID; /* thread ID */
74: unsigned rc; /* return code */
75:
76: sem = 0L; /* init semaphore */
77:
78: /* allocate stack space for thread 1 */
79: /* since this is written in C, DOSALLOCSEG cannot be used here */
80:
81: if ((thread1Stack = malloc(THREAD_STK_SIZE)) == NULL) {
82:
83: printf("thread stack malloc failed\n");
84: DOSEXIT(1, 1); /* terminate all threads and return error */
85: }
86: thread1Stack += THREAD_STK_SIZE; /* since stack grows down */
87:
88: /* start another thread */
89: if (rc = DOSCREATETHREAD( thread1, (unsigned far *) &thread1ID,
90: thread1Stack )) {
91:
92: printf("create of thread failed, error: %d\n", rc);
93: DOSEXIT(1, 1);
94: }
95:
96: thread0(); /* this will loop forever */
97:
98: DOSEXIT(1, 0); /* Terminate all threads and exit */
99: }
100:
101:
102: thread0() /* Thread 0 */
103: {
104: unsigned BytesWrit;
105:
106: for (;;) {
107:
108: /* claim the resource - in this case, the screen */
109:
110: DOSSEMREQUEST( (long) &sem, -1L ); /* no timeout */
111:
112: /* write to the screen */
113:
114: DOSWRITE( 1, (char far *) HELLO0, sizeof(HELLO0) - 1,
115: (unsigned far *) &BytesWrit );
116:
117: DOSSEMCLEAR( (unsigned long) &sem ); /* release resource */
118:
119: DOSSLEEP(2000L); /* give up the processor */
120: }
121: }
122:
123: void far
124: thread1() /* Thread 1 */
125: {
126: unsigned BytesWrit;
127:
128: for (;;) {
129:
130: /* claim the resource - in this case, the screen */
131:
132: DOSSEMREQUEST( (unsigned long) &sem, -1L ); /* no timeout */
133:
134: /* write to the screen */
135:
136: DOSWRITE(1, (char far *)HELLO1, sizeof(HELLO1) - 1,
137: (unsigned far *) &BytesWrit );
138:
139: DOSSEMCLEAR( (unsigned long) &sem ); /* release resource */
140:
141: DOSSLEEP(2000L); /* give up the processor */
142: }
143: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.