|
|
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.