|
|
1.1 root 1: /* 1.1.1.2 ! root 2: * DosCreateThread example. 1.1 root 3: * 1.1.1.2 ! root 4: * Created by Microsoft Corp. 1986 1.1 root 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 1.1.1.2 ! root 9: * the shared resource. See the DosCritSec example for a different method. 1.1 root 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: * 1.1.1.2 ! root 19: * - The thread function must end with a call to DosExit to terminate 1.1 root 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: 1.1.1.2 ! root 55: #define INCL_DOSPROCESS ! 56: #define INCL_DOSSEMAPHORES ! 57: #define INCL_DOSFILEMGR ! 58: ! 59: #include <os2def.h> ! 60: #include <bsedos.h> 1.1 root 61: #include <malloc.h> 1.1.1.2 ! root 62: #undef NULL 1.1 root 63: #include <stdio.h> 64: 1.1.1.2 ! root 65: #define HELLO0 "thread zero hello\r\n" ! 66: #define HELLO1 "THREAD ONE HELLO\r\n" 1.1 root 67: 1.1.1.2 ! root 68: #define THREAD_STK_SIZE 400 /* thread stack size */ 1.1 root 69: 1.1.1.2 ! root 70: HSEM sem; /* ram semaphore */ 1.1 root 71: 72: main(argc, argv) 73: int argc; 74: char *argv[]; 75: { 1.1.1.2 ! root 76: void far thread1(); /* address where thread1 gets control */ ! 77: PSZ thread1Stack; /* far pointer to thread1 stack */ ! 78: TID thread1ID; /* thread ID */ ! 79: unsigned rc; /* return code */ 1.1 root 80: 1.1.1.2 ! root 81: sem = 0L; /* init semaphore */ 1.1 root 82: 1.1.1.2 ! root 83: /* allocate stack space for thread 1 */ ! 84: /* since this is written in C, DosAllocSeg cannot be used here */ 1.1 root 85: 1.1.1.2 ! root 86: if ((thread1Stack = malloc(THREAD_STK_SIZE)) == NULL) { 1.1 root 87: 1.1.1.2 ! root 88: printf("thread stack malloc failed\n"); ! 89: DosExit(EXIT_PROCESS, 1); /* term all threads,return error */ ! 90: } ! 91: thread1Stack += THREAD_STK_SIZE; /* since stack grows down */ 1.1 root 92: 1.1.1.2 ! root 93: /* start another thread */ ! 94: if (rc = DosCreateThread( thread1, &thread1ID, ! 95: thread1Stack )) { 1.1 root 96: 1.1.1.2 ! root 97: printf("create of thread failed, error: %d\n", rc); ! 98: DosExit(EXIT_PROCESS, 1); ! 99: } 1.1 root 100: 1.1.1.2 ! root 101: thread0(); /* this will loop forever */ 1.1 root 102: 1.1.1.2 ! root 103: DosExit(EXIT_PROCESS, 0); /* Terminate all threads and exit */ 1.1 root 104: } 105: 106: 1.1.1.2 ! root 107: thread0() /* Thread 0 */ 1.1 root 108: { 1.1.1.2 ! root 109: USHORT BytesWrit; 1.1 root 110: 111: for (;;) { 112: 1.1.1.2 ! root 113: /* claim the resource - in this case, the screen */ 1.1 root 114: 1.1.1.2 ! root 115: DosSemRequest( &sem, -1L ); /* no timeout */ 1.1 root 116: 1.1.1.2 ! root 117: /* write to the screen */ 1.1 root 118: 1.1.1.2 ! root 119: DosWrite( 1, (char far *) HELLO0, sizeof(HELLO0) - 1, ! 120: &BytesWrit ); 1.1 root 121: 1.1.1.2 ! root 122: DosSemClear( &sem ); /* release resource */ 1.1 root 123: 1.1.1.2 ! root 124: DosSleep(2000L); /* give up the processor */ 1.1 root 125: } 126: } 127: 128: void far 1.1.1.2 ! root 129: thread1() /* Thread 1 */ 1.1 root 130: { 1.1.1.2 ! root 131: USHORT BytesWrit; 1.1 root 132: 133: for (;;) { 134: 1.1.1.2 ! root 135: /* claim the resource - in this case, the screen */ 1.1 root 136: 1.1.1.2 ! root 137: DosSemRequest( &sem, -1L ); /* no timeout */ 1.1 root 138: 1.1.1.2 ! root 139: /* write to the screen */ 1.1 root 140: 1.1.1.2 ! root 141: DosWrite(1, (char far *)HELLO1, sizeof(HELLO1) - 1, ! 142: &BytesWrit ); 1.1 root 143: 1.1.1.2 ! root 144: DosSemClear( &sem ); /* release resource */ 1.1 root 145: 1.1.1.2 ! root 146: DosSleep(2000L); /* give up the processor */ 1.1 root 147: } 148: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.