Purpose
DosCreateThread2 creates an asynchronous thread of execution under the current process using a pre-allocated stack.
Syntax
#define INCL_DOSPROCESS #include os2.h>
APIRET DosCreateThread2
Parameters
ptc(PTHREADCREATE) input/output
typedef struct_THREADCREATE{ ULONG cbSize; PTID pTid; PFNTHREAD pfnStart; ULONG lParam; ULONG lFlag; PBYTE pStack; ULONG cbStack; } THREADCREATE; typedef THREADCREATE *PTHREADCREATE;cbSize (ULONG) input
This function is called using a 32 bit near-call, accepts a single parameter, lParam, and returns a doubleword exit status (see DosExit). Returning from the function without executing DosExit causes the thread to end. In this case, the exit status is the value in the EAX register when the thread ends.
Possible values are a combination of the following
CREATE_READY (0x00000000)
Returns
ulrc (APIRET) returns
DosCreateThread2 returns one of the following values
87
Remarks
The difference between DosCreateThread and DosCreateThread2 is the use and management of the thread's stack.
Using DosCreateThread, the application is not responsible for allocating the stack. The application simply supplies the size of the stack, and the operating system will manage the allocation and location of that storage on behalf of the application. DosCreateThread also employs guard pages and exception handling for stack related situations, such as stack growth. One of the problems with DosCreateThread is that for each thread, a minimum 64K of virtual address space is reserved, but only 8K of physical storage is actually committed. Therefore, 56K of virtual address space is wasted initially.
Using DosCreateThread2, the application is responsible for allocating the stack before calling the API. With DosCreateThread2, the operating system gives the application total control over stack size and location. Therefore, more efficient use of virtual address space within the system can be achieved.
The address of the stack, pStack, must be in the compatibility region, that is, the first 512MB (0x20000000). If DosCreateThread2 is called with a stack address higher than 512MB, ERROR_INVALID_PARAMETER will be returned.
Related Functions
Example Code
In this example, the main thread first allocates 64K worth of memory. It then calls DosCreateThread2 four times to create 4 child threads. Each child thread has 16K of stack space. Finally, the main thread sets the termination flag to allow all child threads to terminate.
Compile this example with MULTITHREAD LIBRARIES. If you are using CSet/2 or VisualAge(R) C/C++, use the /Gm+ switch.
#define INCL_DOSMEMMGR#define INCL_DOSPROCESS #define INCL_DOSERRORS #include os2.h> #include stdio.h> #include stdlib.h> #define _64K 64*1024 #define _48K 48*1024 #define _32K 32*1024 #define _16K 16*1024 void _System TestThread1(void); void _System TestThread2(void); void _System TestThread3(void); void _System TestThread4(void); BOOL flTerminate = FALSE; int main (VOID) { APIRET rc; /* Return code */ void *pStackBase; /* Pointer to stack base */ THREADCREATE tc[4]={0}; /* Thread create structures */ int i; /* Allocate 64K of memory */ rc = DosAllocMem( pStackBase, _64K, PAG_COMMIT | PAG_WRITE); if (rc != NO_ERROR) { printf("DosAllocMem failed, rc=%d\n", rc); return(1); } /* Set up thread structures (4 threads). */ tc[0].cbSize = sizeof(THREADCREATE); tc[0].pfnStart = (PFNTHREAD) TestThread1 tc[0].pStack = (PBYTE)pStackBase + _64K; /* Top of stack (not bottom) */ tc[0].lFlag = CREATE_READY | STACK_SPARSE; tc[0].cbStack = _16K; /* Each thread has 16K stack */ tc[1].cbSize = sizeof(THREADCREATE); tc[1].pfnStart = (PFNTHREAD) TestThread2 tc[1].pStack = (PBYTE)pStackBase + _48K; /* Top of stack (not bottom) */ tc[1].lFlag = CREATE_READY | STACK_SPARSE; tc[1].cbStack = _16K; /* Each thread has 16K stack */ tc[2].cbSize = sizeof(THREADCREATE); tc[2].pfnStart = (PFNTHREAD) TestThread3 tc[2].pStack = (PBYTE)pStackBase + _32K; /* Top of stack (not bottom) */ tc[2].lFlag = CREATE_READY | STACK_SPARSE; tc[2].cbStack = _16K; /* Each thread has 16K stack */ tc[3].cbSize = sizeof(THREADCREATE); tc[3].pfnStart = (PFNTHREAD) TestThread4 tc[3].pStack = (PBYTE)pStackBase + _16K; /* Top of stack (not bottom) */ tc[3].lFlag = CREATE_READY | STACK_SPARSE; tc[3].cbStack = _16K; /* Each thread has 16K stack */ /* Create 4 child threads. */ for (i=0; i 4; i++) { rc = DosCreateThread2( tc[i]); if (rc != NO_ERROR) { printf( "DosCreateThread2 failed, rc = %d\n", rc); return(1); } else printf("DosCreateThread2 was successful, tid=%d\n", tc[i].pTid); } flTerminate = TRUE; /* Wait for all child threads to terminate. */ for (i=0; i 4; i++) { DosWaitThread( (tc[i].pTid), DCWW_WAIT); } DosFreeMem(pStackBase); return(0); } void _System TestThread1(void) { APIRET rc; PTIB ptib; PPIB ppib; rc = DosGetInfoBlocks( ptib, ppib); if (rc != NO_ERROR) { printf("TestThread1 DosGetInfoBlocks failed rc = %d\n", rc); return; } printf("TestThread1 base of stack at 0x%08X, top of stack at 0x%08X\n", ptib->tib_pstack, ptib->tib_pstacklimit); while (flTerminate == FALSE) { DosSleep(1000); } } void _System TestThread2(void) { APIRET rc; PTIB ptib; PPIB ppib; rc = DosGetInfoBlocks( ptib, ppib); if (rc != NO_ERROR) { printf("TestThread2 DosGetInfoBlocks failed rc = %d\n", rc); return; } printf("TestThread2 base of stack at 0x%08X, top of stack at 0x%08X\n", ptib->tib_pstack, ptib->tib_pstacklimit); while (flTerminate == FALSE) { DosSleep(1000); } } void _System TestThread3(void) { APIRET rc; PTIB ptib; PPIB ppib; rc = DosGetInfoBlocks( ptib, ppib); if (rc != NO_ERROR) { printf("TestThread3 DosGetInfoBlocks failed rc = %d\n", rc); return; } printf("TestThread3 base of stack at 0x%08X, top of stack at 0x%08X\n", ptib->tib_pstack, ptib->tib_pstacklimit); while (flTerminate == FALSE) { DosSleep(1000); } } void _System TestThread4(void) { APIRET rc; PTIB ptib; PPIB ppib; rc = DosGetInfoBlocks( ptib, ppib); if (rc != NO_ERROR) { printf("TestThread4 DosGetInfoBlocks failed rc = %d\n", rc); return; } printf("TestThread4 base of stack at 0x%08X, top of stack at 0x%08X\n", ptib->tib_pstack, ptib->tib_pstacklimit); while (flTerminate == FALSE) { DosSleep(1000); } }