|
|
Microsoft OS/2 SDK 03-01-1988
/*
* DosCreateThread example.
*
* Created by Microsoft Corp. 1986
*
* This example illustrates the use of threads and ram semaphores.
* Two threads are given alternating access to a shared resource, in this
* case, the screen. In this example a semaphore is used to protect
* the shared resource. See the DosCritSec example for a different method.
*
* See example program "asmexmpl" for a version of this program in assembler.
*
* In general, threads in C are a little tricky, and require that the
* programmer be aware of the following issues:
*
* - C functions can be used as thread bodies. The function must have
* no arguments.
*
* - The thread function must end with a call to DosExit to terminate
* either that thread or all threads. Simply returning, or falling
* off the end will lead to unpredictable results.
*
* - The C runtimes are not generally reentrant. If you call the
* runtime from more than one thread you need to protect it from
* being reentered using a semaphore.
*
*
* - Some of the C runtimes are built with stack checking enabled (see
* section 2.5 of the C run-time library reference). The stack checking
* depends on SS==DS. If you use these runtimes, you must allocate
* stack space for any threads from the default data segment and you
* must use the small- or medium- memory models. That way, you will
* have SS==DS in these threads. This is accomplished by using malloc,
* which maps to _nmalloc in near-data models (small- and medium- models).
* _nmalloc allocates memory from within the default data segment.
*
* The general solution is to use the -Aw option to tell the compiler that
* SS!=DS and not use the C runtimes which do stack checking (printf, etc.).
* Also, you must use the -Gs option to turn off stack checking in your
* program. For examples of the -Au option (SS!=DS and DS reloaded on
* function entry) see the dynlink demo.
*
*
* - Threads can have local variables. When accessing global data be
* careful about critical sections and collisions with other threads.
* Be especially careful of modifications to data structures which are
* not atomic operations. For example if you have a LONG INT in global
* data, and two threads access it, then you need a critical section
* around the code which accesses it, since the 286 is a 16 bit machine
* and the compiler has to generate multiple instructions to modify a
* long in memory. If one thread preempts another while it is half
* through modifying the LONG, it is left in an inconsistent state.
*/
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#define INCL_DOSFILEMGR
#include <os2def.h>
#include <bsedos.h>
#include <malloc.h>
#undef NULL
#include <stdio.h>
#define HELLO0 "thread zero hello\r\n"
#define HELLO1 "THREAD ONE HELLO\r\n"
#define THREAD_STK_SIZE 400 /* thread stack size */
HSEM sem; /* ram semaphore */
main(argc, argv)
int argc;
char *argv[];
{
void far thread1(); /* address where thread1 gets control */
PSZ thread1Stack; /* far pointer to thread1 stack */
TID thread1ID; /* thread ID */
unsigned rc; /* return code */
sem = 0L; /* init semaphore */
/* allocate stack space for thread 1 */
/* since this is written in C, DosAllocSeg cannot be used here */
if ((thread1Stack = malloc(THREAD_STK_SIZE)) == NULL) {
printf("thread stack malloc failed\n");
DosExit(EXIT_PROCESS, 1); /* term all threads,return error */
}
thread1Stack += THREAD_STK_SIZE; /* since stack grows down */
/* start another thread */
if (rc = DosCreateThread( thread1, &thread1ID,
thread1Stack )) {
printf("create of thread failed, error: %d\n", rc);
DosExit(EXIT_PROCESS, 1);
}
thread0(); /* this will loop forever */
DosExit(EXIT_PROCESS, 0); /* Terminate all threads and exit */
}
thread0() /* Thread 0 */
{
USHORT BytesWrit;
for (;;) {
/* claim the resource - in this case, the screen */
DosSemRequest( &sem, -1L ); /* no timeout */
/* write to the screen */
DosWrite( 1, (char far *) HELLO0, sizeof(HELLO0) - 1,
&BytesWrit );
DosSemClear( &sem ); /* release resource */
DosSleep(2000L); /* give up the processor */
}
}
void far
thread1() /* Thread 1 */
{
USHORT BytesWrit;
for (;;) {
/* claim the resource - in this case, the screen */
DosSemRequest( &sem, -1L ); /* no timeout */
/* write to the screen */
DosWrite(1, (char far *)HELLO1, sizeof(HELLO1) - 1,
&BytesWrit );
DosSemClear( &sem ); /* release resource */
DosSleep(2000L); /* give up the processor */
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.