home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / msysjour / vol04 / 02a / os2hello / hello0.c < prev    next >
C/C++ Source or Header  |  1988-12-01  |  8KB  |  297 lines

  1. /* hello0.c RHS 10/14/88
  2.  *
  3.  * OS/2 and 1988 version of K&R's hello.c
  4.  * demonstrates multiple threads
  5.  */
  6.  
  7. /*
  8. This program provides an introduction to the use of threads and semaphores
  9. under OS/2.  It divides the screen up into a series of logical frames.
  10. Each frame is a portion of the screen that is managed (written to) by a
  11. single thread.    The exact number of frames will depend on the current
  12. screen length (25, 43 and 50 lines).  Each thread has its own data from
  13. which it knows where the frame can be found on screen.    This includes
  14. a semaphore which signals the thread when to proceed.  These elements can
  15. be found in the FRAME data type.
  16.  
  17. Upon receiving a signal from its semaphore (i.e., the semphore has been
  18. cleared), the thread either draws a message on the frame or clears the
  19. frame, and reverses the flag that determines this.    Then it again blocks
  20. until its semaphore has been cleared again.
  21.  
  22. The main program thread starts by setting up the frame information:
  23. checking the screen size, determining the number and size of the frames.
  24. It also "randomly" selects the order in which the frames will appear.
  25.  
  26. Then it sets each thread's semaphore, and initiates each thread (remember
  27. the threads will block until their semphores are cleared.
  28.  
  29. Finally, the main program goes into an infinite loop, clearing each thread's
  30. semaphore, sleeping for at least 1 millisecond, and then continuing to the
  31. next thread.  Thus the threads asynchronously call the VIO subsystem to
  32. draw or clear each frame, while the main program thread continues.
  33.  
  34. An optional parameter can be passed to set the number of milliseconds passed
  35. to DosSleep, allowing the operator to more accurately "see" the order in
  36. which the frames appear/erase.    This value must always be at least 1 to
  37. allow the main program thread to give time to the CPU scheduler.
  38.  
  39. A call to _beginthread() early in main() sets up a thread to monitor key
  40. board input.  This thread blocks until a key is pressed, then examines the
  41. key, and if they is the Escape Key (27 decimal or 1bH), the thread calls
  42. DosExit to kill the whole process.
  43.  
  44.  */
  45.  
  46. #define INCL_SUB
  47. #define INCL_DOS
  48. #include<stdio.h>
  49. #include<string.h>
  50. #include<assert.h>
  51. #include<stdlib.h>
  52. #include<process.h>
  53. #include<os2.h>
  54.  
  55. #if !defined(TRUE)
  56. #define TRUE    1
  57. #endif
  58.  
  59. #if !defined(FALSE)
  60. #define FALSE    0
  61. #endif
  62.  
  63. #define LINES25     4                            /* height in lines of frames*/
  64. #define LINES43     6
  65. #define LINES50     7
  66.  
  67. #define RANDOMIZER    5
  68. #define MAXFRAMES    28                            /* limited to max frames
  69. possible */
  70. #define RAND()        (rand() % maxframes);
  71. #define THREADSTACK 400                         /* size of stack each thread*/
  72. #define IDCOL        15
  73. #define ESC         0x1b
  74.  
  75. char *blank_str =                                /* string for blanking frame*/
  76.     "                    ";
  77.  
  78.     /* frame data *************************/
  79. char *hello_str25[LINES25+1] =
  80.     {
  81.     "╒══════════════════╕",
  82.     "│   Hello, world!  │",
  83.     "│ from Thread #    │",
  84.     "╘══════════════════╛",
  85.     "\0"
  86.     };
  87.  
  88. char *hello_str43[LINES43+1] =
  89.     {
  90.     "╒══════════════════╕",
  91.     "│                  │",
  92.     "│   Hello, world!  │",
  93.     "│ from Thread #    │",
  94.     "│                  │",
  95.     "╘══════════════════╛",
  96.     "\0"
  97.     };
  98.  
  99. char *hello_str50[LINES50+1] =
  100.     {
  101.     "╒══════════════════╕",
  102.     "│                  │",
  103.     "│   Hello, world!  │",
  104.     "│                  │",
  105.     "│ from Thread #    │",
  106.     "│                  │",
  107.     "╘══════════════════╛",
  108.     "\0"
  109.     };
  110.  
  111.  
  112. char **helloptr;
  113. int numlines;
  114.  
  115. typedef struct _frame                            /* frame structure            */
  116.     {
  117.     unsigned    frame_cleared;
  118.     unsigned    row;
  119.     unsigned    col;
  120.     unsigned    threadid;
  121.     long        startsem;
  122.     char        threadstack[THREADSTACK];
  123.     } FRAME;
  124.  
  125. FRAME far *frames[MAXFRAMES];                    /* pointers to frames        */
  126. unsigned maxframes;
  127. unsigned curframe;
  128. long sleeptime = 1L;                            /* minim sleep time         */
  129. char keythreadstack[THREADSTACK];
  130.  
  131.     /* function prototypes ***************************/
  132. void hello_thread(FRAME far *frameptr);
  133. void keyboard_thread(void);
  134. void main(int argc, char **argv);
  135.  
  136.  
  137. void main(int argc, char **argv)
  138.     {
  139.     int row, col, maxrows, maxcols, len, i, loops = 0;
  140.     VIOMODEINFO viomodeinfo;
  141.  
  142.     if(argc > 1)
  143.         sleeptime = atol(argv[1]);
  144.     if(sleeptime < 1L)
  145.         sleeptime = 1L;
  146.  
  147.                                                 /* start keyboard thread    */
  148.     if(_beginthread(keyboard_thread,keythreadstack,THREADSTACK,NULL) == -1)
  149.         exit(-1);
  150.  
  151.     viomodeinfo.cb = sizeof(viomodeinfo);
  152.     VioGetMode(&viomodeinfo,0);                 /* get video info            */
  153.  
  154.     maxrows = viomodeinfo.row;
  155.     maxcols = viomodeinfo.col;
  156.  
  157.     switch(maxrows)
  158.         {
  159.         case 25:
  160.             helloptr = hello_str25;
  161.             numlines = LINES25;
  162.             break;
  163.         case 43:
  164.             helloptr = hello_str43;
  165.             numlines = LINES43;
  166.             break;
  167.         case 50:
  168.             helloptr = hello_str50;
  169.             numlines = LINES50;
  170.             break;
  171.         default:                                /* fail if not 25,43,50 lines*/
  172.             assert(0);
  173.             exit(-1);
  174.         }
  175.  
  176.     len = strlen(*helloptr);
  177.  
  178.     maxframes = (maxrows / numlines) * (maxcols / len);
  179.  
  180.     assert(maxframes <= MAXFRAMES);
  181.  
  182.     for( i = 0; i < maxframes; i++)             /* initialize structures    */
  183.         {
  184.         if(!(frames[i] = malloc(sizeof(FRAME))))
  185.             exit(0);
  186.         frames[i]->frame_cleared = FALSE;
  187.         frames[i]->startsem = 0L;
  188.         memset(frames[i]->threadstack,0xff,sizeof(frames[i]->threadstack));
  189.         }
  190.  
  191.     i = RAND();                                 /* get first random frame    */
  192.  
  193.                                                 /* set up random appearance */
  194.     for(row = col = 0; loops < maxframes ; )    /* set row/col each frame    */
  195.         {
  196.         if(!frames[i]->frame_cleared)
  197.             {
  198.             frames[i]->frame_cleared = TRUE;    /* set for empty frame        */
  199.             frames[i]->row = row;                /* frame upper row            */
  200.             frames[i]->col = col;                /* frame left column        */
  201.  
  202.             col += len;                         /* next column on this row    */
  203.  
  204.             if(col >= maxcols)                    /* go to next row?            */
  205.                 {
  206.                 col = 0;                        /* reset for start column    */
  207.                 row += numlines;                /* set for next row         */
  208.                 }
  209.  
  210.             i = RAND();                         /* get next random frame    */
  211.             }
  212.         else
  213.             ++i;
  214.  
  215.         if(i >= maxframes)
  216.             {
  217.             i -= maxframes;
  218.             loops++;                            /* keep track of # of frames*/
  219.             }
  220.         }
  221.  
  222.  
  223.     for( i = 0 ; i < maxframes; i++)            /* start a thread for each    */
  224.         {
  225.         DosSemSet(&frames[i]->startsem);        /* initially set each sem.    */
  226.  
  227.                                                 /* start each thread        */
  228.         if((frames[i]->threadid = _beginthread(
  229.                 (void far *)hello_thread,
  230.                 (void far *)frames[i]->threadstack,
  231.                 THREADSTACK,
  232.                 (void far *)frames[i])) == -1)
  233.             {
  234.             maxframes = i;                        /* reset maxframes on failure*/
  235.             break;
  236.             }
  237.         }
  238.  
  239.     while(TRUE)                                 /* main loop                */
  240.         {
  241.                                 /* swing thru frames, signalling to threads */
  242.         for( i = 0; i < maxframes; i++)
  243.             {
  244.             DosSemClear(&frames[i]->startsem);    /* clear: thread can go     */
  245.             DosSleep(sleeptime);                /* sleep a little            */
  246.             }
  247.         }
  248.     }
  249.  
  250.  
  251. void hello_thread(FRAME far *frameptr)            /* frame thread function    */
  252.     {
  253.     register char **p;
  254.     register int line;
  255.     int len = strlen(*helloptr);
  256.     unsigned row, col = frameptr->col;
  257.     char idstr[20];
  258.  
  259.     while(TRUE)
  260.         {
  261.         DosSemRequest(&frameptr->startsem,-1L);     /* block until cleared    */
  262.         itoa(frameptr->threadid,idstr,10);            /* init idstr            */
  263.  
  264.         row = frameptr->row;                        /* reset row            */
  265.  
  266.         if(!frameptr->frame_cleared)                /* if frame in use, erase*/
  267.             for( line = 0; line < numlines; line++, row++)
  268.                 VioWrtCharStr(blank_str,len,row,col,0);
  269.         else                                        /* else frame not in use*/
  270.             {
  271.             p = helloptr;                            /* print message        */
  272.             for( line = 0; **p; line++, row++, p++)
  273.                 VioWrtCharStr(*p,len,row,col,0);
  274.                                                     /* write id # in frame    */
  275.             VioWrtCharStr(idstr,3,row-(numlines/2),IDCOL+col,0);
  276.             }
  277.         frameptr->frame_cleared = !frameptr->frame_cleared;/*toggle use flag
  278. */
  279.         }
  280.     }
  281.  
  282. void keyboard_thread(void)
  283.     {
  284.     KBDKEYINFO keyinfo;
  285.  
  286.     while(TRUE)
  287.         {
  288.         KbdCharIn(&keyinfo,IO_WAIT,0);            /* wait for keystroke        */
  289.         if(keyinfo.chChar == ESC)                /* if ESC pressed, break    */
  290.             break;
  291.         }
  292.     DosExit(EXIT_PROCESS,0);                    /* terminate the process    */
  293.     }
  294.  
  295.     /******** end of hello0.c *********/
  296.  
  297.