Annotation of os232sdk/toolkt20/c/samples/template/thrd.c, revision 1.1.1.1

1.1       root        1: /*==============================================================*\
                      2:  *  Thrd.c - background thread and associated routines
                      3:  *      Created 1989, 1990 Microsoft Corp.
                      4:  *--------------------------------------------------------------
                      5:  *
                      6:  *  This module contains the code for a background processing
                      7:  *  thread as well as the code for any routines used in that thread.
                      8:  *
                      9:  *  This thread uses an object window to facilitate communication
                     10:  *  with the main thread.  The main thread can communicate with
                     11:  *  the background thread through messages.  You define your
                     12:  *  own window messages in main.h, post or send them to the
                     13:  *  background thread through the routines provided in this file,
                     14:  *  and then process the messages in the ObjectWndProc() routine.
                     15:  *  The object window then sends other messages back to the
                     16:  *  main window to notify the main window as to the status of the
                     17:  *  task or with the final result.
                     18:  *
                     19:  *  An object window is used as the main window of the thread
                     20:  *  for several reasons.  The window is hidden, so it is never
                     21:  *  displayed on the screen.  Since it is hidden, the window
                     22:  *  does not have to process most of the window messages that are
                     23:  *  processed by visible windows, e.g. WM_PAINT, WM_SIZE,
                     24:  *  WM_SETFOCUS, etc.  This window will never receive the focus
                     25:  *  so it does not have to process input messages.  You can, however,
                     26:  *  send all mouse and keyboard messages to this window and have
                     27:  *  it process all input if you wish.  Since the window does not
                     28:  *  belong to any focus or activation chains, you can block this
                     29:  *  thread on a semaphore without having the system lock up or use
                     30:  *  the window manager semaphore routines (WinMsgSemWait(), etc.).
                     31:  *
                     32:  *  NOTE:  The BackgroundThread() routine is designed to create only
                     33:  *          one thread.  In fact, should you try to create another
                     34:  *          one the call will fail.  The thread uses several variables
                     35:  *          which are defined globally within this module.  In order
                     36:  *          to enable this routine to create multiple threads, you
                     37:  *          will need to make these variables local.  You will also need
                     38:  *          to differentiate between the different object windows
                     39:  *          created so that you can specify which thread will
                     40:  *          receive a posted message.
                     41:  *
                     42:  *  In order to enable the use of the second thread, define the
                     43:  *  BACKGROUND_THREAD constant found in main.h
                     44:  *
                     45:  *--------------------------------------------------------------
                     46:  *
                     47:  *  This source file contains the following functions:
                     48:  *
                     49:  *      BackgroundThread() - routine for the background thread
                     50:  *      CreateBackgroundThread() - routine that creates background thread
                     51:  *      DestroyBackgroundThread() - routine that destroys the thread
                     52:  *      PostBkThreadMsg(msg, mp1, mp2) - posts a msg to the thread
                     53:  *      SendBkThreadMsg(msg, mp1, mp2) - sends a msg to the thread
                     54:  *      ObjectWndProc(hwnd, msg, mp1, mp2) - Object window procedure
                     55:  *
                     56: \*==============================================================*/
                     57: 
                     58: /*--------------------------------------------------------------*\
                     59:  *  Include files, macros, defined constants, and externs
                     60: \*--------------------------------------------------------------*/
                     61: 
                     62: #define  INCL_DOSPROCESS
                     63: #define  INCL_DOSSEMAPHORES
                     64: 
                     65: #include <os2.h>
                     66: #include "main.h"
                     67: #include "xtrn.h"
                     68: 
                     69: #define THREADSTACKSIZE     8192L
                     70: #define SEM_TIMEOUT        10000L
                     71: 
                     72: /*--------------------------------------------------------------*\
                     73:  *  Global variables
                     74: \*--------------------------------------------------------------*/
                     75: static HAB habBkThread;
                     76: static HMQ hmqBkThread;
                     77: static TID tidBkThread;
                     78: static HWND hwndObject;
                     79: static CHAR szObjectClass[MAXNAMEL];
                     80: static BOOL fThreadCreated = FALSE;
                     81: static HEV hevThreadInit;   /* semaphore for thread initialization */
                     82: 
                     83: /*--------------------------------------------------------------*\
                     84:  *  Entry point declarations
                     85: \*--------------------------------------------------------------*/
                     86: VOID BackgroundThread(ULONG ulThreadParam);
                     87: MRESULT EXPENTRY ObjectWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2);
                     88: 
                     89: 
                     90: /****************************************************************\
                     91:  *  Background thread routine
                     92:  *--------------------------------------------------------------
                     93:  *
                     94:  *  Name:   BackgroundThread(ulThreadParam)
                     95:  *
                     96:  *  Purpose: Routine is a background thread used for tasks to be
                     97:  *           completed in the background.
                     98:  *
                     99:  *  Usage:  Routine is called at initialization time to create
                    100:  *          a background processing thread.
                    101:  *
                    102:  *  Method: The routine initializes itself as a PM thread and creates
                    103:  *          a message queue.  It then creates an object window
                    104:  *          through which it will receive and send messages.
                    105:  *          It then polls through a message loop, processing any
                    106:  *          messages it receives in the object window's window
                    107:  *          procedure.  When the loop ends, it terminates.
                    108:  *
                    109:  *  Returns:
                    110:  *
                    111: \****************************************************************/
                    112: VOID BackgroundThread(ulThreadParam)
                    113: ULONG ulThreadParam;        /* parameter passed into DosCreateThread() */
                    114: {
                    115:     QMSG qmsg;
                    116: 
                    117:     /* create message queue for thread */
                    118:     habBkThread = WinInitialize(0);
                    119:     if(habBkThread == NULL)  {
                    120:         WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL);
                    121:         DosExit(EXIT_THREAD, NULL);
                    122:     }
                    123: 
                    124:     hmqBkThread = WinCreateMsgQueue(habBkThread, 0);
                    125:     if(hmqBkThread == NULL)  {
                    126:         WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL);
                    127: 
                    128:         WinTerminate(habBkThread);
                    129:         DosExit(EXIT_THREAD, NULL);
                    130:     }
                    131: 
                    132:     /* load the string for the object window class and register the class */
                    133:     if(!WinLoadString(habBkThread,
                    134:                       NULL,
                    135:                       IDS_OBJECTCLASS,
                    136:                       MAXNAMEL,
                    137:                       (PSZ)szObjectClass))  {
                    138:         WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL);
                    139: 
                    140:         goto ExitBkThread;
                    141:     }
                    142: 
                    143:     /* register the main client window class */
                    144:     if(!WinRegisterClass(habBkThread,
                    145:                         (PSZ)szObjectClass,
                    146:                         (PFNWP)ObjectWndProc,
                    147:                         0,
                    148:                         0))  {
                    149: 
                    150:         WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL);
                    151: 
                    152:         goto ExitBkThread;
                    153:     }
                    154: 
                    155: 
                    156:     /* create the object window */
                    157:     hwndObject = WinCreateWindow(HWND_OBJECT,
                    158:                                  szObjectClass,
                    159:                                  NULL,
                    160:                                  NULL,
                    161:                                  0,
                    162:                                  0,
                    163:                                  0,
                    164:                                  0,
                    165:                                  NULL,
                    166:                                  HWND_TOP,
                    167:                                  OBJECTID,
                    168:                                  NULL,
                    169:                                  NULL);
                    170: 
                    171:     if(hwndObject == NULL)  {
                    172:         WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL);
                    173: 
                    174:         goto ExitBkThread;
                    175:     }
                    176: 
                    177:     /* set thread created flag so another thread of this type
                    178:        cannot be created */
                    179:     fThreadCreated = TRUE;
                    180: 
                    181:     /* clear initialization semaphore */
                    182:     DosPostEventSem(hevThreadInit);
                    183: 
                    184: 
                    185:     /* message loop */
                    186:     while(WinGetMsg(hmqBkThread, (PQMSG)&qmsg, NULL, NULL, NULL))
                    187:         WinDispatchMsg(hmqBkThread, (PQMSG)&qmsg);
                    188: 
                    189: ExitBkThread:
                    190: 
                    191:     /* destroy object window, clean up message queue and terminate */
                    192:     if(WinIsWindow(habBkThread, hwndObject))
                    193:         WinDestroyWindow(hwndObject);
                    194: 
                    195:     WinDestroyMsgQueue(hmqBkThread);
                    196:     WinTerminate(habBkThread);
                    197: 
                    198:     /* If termination is due to an error initializing the thread, then
                    199:         clear the initialization semaphore so that the main thread
                    200:         can continue. */
                    201:     if(!fThreadCreated)
                    202:         DosPostEventSem(hevThreadInit);
                    203: 
                    204: 
                    205:     /*------------------------------------------------------------------*
                    206:      *
                    207:      *  Note: C-runtime considerations:
                    208:      *
                    209:      *  If you use non-reentrant C runtime functions in the second thread,
                    210:      *  then you should use call _endthread here instead of DosExit().
                    211:      *  See the comment in the CreateBackgroundThread() routine for
                    212:      *  more information.
                    213:      *
                    214:      *------------------------------------------------------------------*/
                    215:     DosExit(EXIT_THREAD, NULL);
                    216: 
                    217:     /* the thread parameter is not currently used */
                    218:     ulThreadParam;
                    219: 
                    220: }   /* BackgroundThread() */
                    221: 
                    222: 
                    223: /****************************************************************\
                    224:  *  Creates the Background thread
                    225:  *--------------------------------------------------------------
                    226:  *
                    227:  *  Name:   CreateBackgroundThread()
                    228:  *
                    229:  *  Purpose: Routine creates the background thread
                    230:  *
                    231:  *  Usage:  Routine is called at initialization time to create
                    232:  *          a background processing thread.
                    233:  *
                    234:  *  Method: The routine calls DosCreateThread with the Background
                    235:  *          thread routine.
                    236:  *
                    237:  *  Returns: TRUE if thread is created successfully, FALSE if not
                    238:  *              or if the thread was already created
                    239:  *
                    240: \****************************************************************/
                    241: BOOL CreateBackgroundThread(VOID)
                    242: {
                    243:     SHORT sRet;
                    244: 
                    245:     /*------------------------------------------------------------------*
                    246:      *
                    247:      *  Note: C-runtime considerations:
                    248:      *
                    249:      *  If you use non-reentrant C runtime functions in the second thread,
                    250:      *  then you will need to use _beginthread and _endthread instead of
                    251:      *  DosCreateThread and DosExit.  In addition, you will have
                    252:      *  to link with LIBCMT.LIB instead of LIBC.LIB, and you will
                    253:      *  have use -D_MT as a compiler option.
                    254:      *
                    255:      *------------------------------------------------------------------*/
                    256: 
                    257: 
                    258:     if(!fThreadCreated)  {
                    259:         DosCreateEventSem((PSZ)NULL, &hevThreadInit, 0L, FALSE);
                    260:         sRet = DosCreateThread(&tidBkThread,
                    261:                                (PFNTHREAD)BackgroundThread,
                    262:                                0L,
                    263:                                0L,
                    264:                                THREADSTACKSIZE);
                    265:     } else
                    266:         return FALSE;
                    267: 
                    268:     /* wait until the thread has finished initialization */
                    269:     if(DosWaitEventSem(hevThreadInit, SEM_TIMEOUT))
                    270:         return FALSE;
                    271: 
                    272:     return((BOOL)(sRet == 0));
                    273: 
                    274: }   /* CreateBackgroundThread() */
                    275: 
                    276: 
                    277: /****************************************************************\
                    278:  *  Destroys the Background thread
                    279:  *--------------------------------------------------------------
                    280:  *
                    281:  *  Name:   DestroyBackgroundThread()
                    282:  *
                    283:  *  Purpose: Routine destroys the background thread
                    284:  *
                    285:  *  Usage:  Routine is called at exit time to destroy the background
                    286:  *          processing thread.
                    287:  *
                    288:  *  Method: The routine posts a WM_CLOSE message to the object window
                    289:  *          to end its message loop.  It then waits to make sure that the
                    290:  *          thread has been terminated before it returns.
                    291:  *
                    292:  *  Returns:
                    293:  *
                    294: \****************************************************************/
                    295: VOID DestroyBackgroundThread(VOID)
                    296: {
                    297: 
                    298:     PostBkThreadMsg(WM_CLOSE, NULL, NULL);
                    299: 
                    300:     DosWaitThread(&tidBkThread, 0);
                    301: 
                    302: }   /* DestroyBackgroundThread() */
                    303: 
                    304: 
                    305: /****************************************************************\
                    306:  *  Posts a message to the Background thread
                    307:  *--------------------------------------------------------------
                    308:  *
                    309:  *  Name:   PostBkThreadMsg()
                    310:  *
                    311:  *  Purpose: Routine posts a message to the object window of the
                    312:  *           background thread.
                    313:  *
                    314:  *  Usage:  Routine is called whenever a message is to be posted to
                    315:  *          the background processing thread.
                    316:  *
                    317:  *  Method: The routine posts the message to the object window of the
                    318:  *          thread.
                    319:  *
                    320:  *  Returns: the return value from WinPostMsg().
                    321:  *
                    322: \****************************************************************/
                    323: BOOL PostBkThreadMsg(msg, mp1, mp2)
                    324: USHORT msg;     /* message id */
                    325: MPARAM mp1;     /* first parameter */
                    326: MPARAM mp2;     /* second parameter */
                    327: {
                    328: 
                    329:     return(WinPostMsg(hwndObject, msg, mp1, mp2));
                    330: 
                    331: }   /* PostBkThreadMsg() */
                    332: 
                    333: 
                    334: /****************************************************************\
                    335:  *  Sends a message to the Background thread
                    336:  *--------------------------------------------------------------
                    337:  *
                    338:  *  Name:   SendBkThreadMsg()
                    339:  *
                    340:  *  Purpose: Routine sends a message to the object window of the
                    341:  *           background thread.
                    342:  *
                    343:  *  Usage:  Routine is called whenever a message is to be sent to
                    344:  *          the background processing thread.
                    345:  *
                    346:  *  Method: The routine sends the message to the object window of the
                    347:  *          thread.
                    348:  *
                    349:  *  Returns: the return value from WinSendMsg().
                    350:  *
                    351: \****************************************************************/
                    352: MRESULT SendBkThreadMsg(msg, mp1, mp2)
                    353: USHORT msg;     /* message id */
                    354: MPARAM mp1;     /* first parameter */
                    355: MPARAM mp2;     /* second parameter */
                    356: {
                    357: 
                    358:     return(WinSendMsg(hwndObject, msg, mp1, mp2));
                    359: 
                    360: }   /* SendBkThreadMsg() */
                    361: 
                    362: 
                    363: /****************************************************************\
                    364:  *  Dialog procedure for the Object window
                    365:  *--------------------------------------------------------------
                    366:  *
                    367:  *  Name:   ObjectWndProc(hwnd, msg, mp1, mp2)
                    368:  *
                    369:  *  Purpose: Processes all messages sent to the Object window
                    370:  *
                    371:  *  Usage:  Called for each message sent to the Object window.
                    372:  *
                    373:  *  Method: the Object window processes the messages that tell
                    374:  *          the background thread what action to take.  Since
                    375:  *          the object window is not visible, it will not
                    376:  *          process any of the standard window messages.
                    377:  *
                    378:  *  Returns: Dependent upon message sent
                    379:  *
                    380: \****************************************************************/
                    381: MRESULT EXPENTRY ObjectWndProc(hwnd, msg, mp1, mp2)
                    382: HWND hwnd;      /* handle of window */
                    383: USHORT msg;     /* id of message */
                    384: MPARAM mp1;     /* first message parameter */
                    385: MPARAM mp2;     /* second message parameter */
                    386: {
                    387: 
                    388:     switch(msg)  {
                    389: 
                    390:         /*--------------------------------------------------------------*\
                    391:          *  Include any user defined messages to determine which
                    392:          *  action the background thread should take
                    393:         \*--------------------------------------------------------------*/
                    394: 
                    395:         default:
                    396:             return (WinDefWindowProc(hwnd, msg, mp1, mp2));
                    397:             break;
                    398:     }
                    399: 
                    400:     return 0L;
                    401: 
                    402:     hwnd;
                    403:     mp1;
                    404:     mp2;
                    405: 
                    406: }   /* ObjectWndProc() */

unix.superglobalmegacorp.com

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