File:  [OS/2 SDKs] / os2sdk / demos / examples / threads / threads.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:26:18 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: os2sdk-1988, HEAD
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 */
    }
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.