/******************************************************************************/
/* SAMPLE PROGRAM 02: SAMPLE02.C                                              */
/*                                                                            */
/* COPYRIGHT:                                                                 */
/* ----------                                                                 */
/* Copyright (C) International Business Machines Corp., 1991,1995.            */
/*                                                                            */
/* DISCLAIMER OF WARRANTIES:                                                  */
/* -------------------------                                                  */
/* The following [enclosed] code is sample code created by IBM                */
/* Corporation.  This sample code is not part of any standard IBM product     */
/* and is provided to you solely for the purpose of assisting you in the      */
/* development of your applications.  The code is provided "AS IS",           */
/* without warranty of any kind.  IBM shall not be liable for any damages     */
/* arising out of your use of the sample code, even if they have been         */
/* advised of the possibility of such damages.                                */
/*                                                                            */
/******************************************************************************/
/*                                                                            */
/*  Sample to demonstrate a multithread program                               */
/*                                                                            */
/*  This program demonstrates the multithread programming capability          */
/*  of the IBM VisualAge C++ compiler.                                        */
/*                                                                            */
/*  This sample program creates one thread for each argument.  Each           */
/*  thread prints "Hello world from thread n!" the number of times            */
/*  specified in the corresponding argument.  For example                     */
/*                                                                            */
/*     SAMPLE02 2 4 6                                                         */
/*                                                                            */
/*  creates three threads; the first thread displays "Hello"                  */
/*  two times, the second thread displays "Hello" four times,                 */
/*  and the third thread displays "Hello" six times.                          */
/*                                                                            */
/*  In operation, the program works in the following order:                   */
/*                                                                            */
/*     1. Creates the requested number of threads                             */
/*     2. Waits until all threads have been created                           */
/*     3. Begins multithread execution and waits for completion               */
/*                                                                            */
/******************************************************************************/

#define  INCL_DOS
#include <os2.h>
#include <malloc.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>


int main( int argc, char * argv[] );
void childcode( void * arg );

typedef struct            /* the thread information structure          */
{                         /*                                           */
   unsigned count;        /* the number of times to display the text   */
   HEV      hev  ;        /* the individual thread's event semaphore   */
}  THREAD_INFO ;          /* handle                                    */

HEV      hev ;            /* the main thread's event semaphore handle  */

int main( int argc, char *argv[])
{
   int i, rc;
   int NumThreads;
   THREAD_INFO thread_info[9];

   int MaxThread = 0;

   if ( argc == 1 ) {
      printf( "*** The syntax is sample01 <agr1> <arg2> ... <up to 9 args>\n");
      return (-1);
   }

   if ( argc > 10 ) {
      printf( "*** Error: Too many arguments (maximum 9 arguments)\n");
      return (-1);
   }


   /*       Create the main thread's event semaphore        */

   DosCreateEventSem(NULL,         /* this is an anonymous semaphore          */
                     &hev,         /* a pointer to receive a semaphore handle */
                     0L,           /* this is a private semaphore             */
                     FALSE);       /* initial state of the semaphore is       */
                                   /* owned.                                  */

   /*  Create one thread for each argument   */

   NumThreads = 1; /* the main thread counts as one */

   /*  Create a new thread and pass the corresponding argument  */

   for (i=1; i < argc ; i++ ) {

    /*       Create an event semaphore for a child thread    */

     thread_info[i-1].count  = (unsigned) atol( argv[i] ) ;

     DosCreateEventSem(NULL,
                       &thread_info[i-1].hev,
                       0L,
                       FALSE);

     rc = _beginthread( childcode,
                        NULL,
                        8192,
                        (void *) &thread_info[i-1]);

     /* Check for error and keep track of how many threads were created   */

     if (rc == -1) {
        printf("*** Error: Could not create %d-th Thread ***\n",
                NumThreads + 1);
     } else NumThreads++;

     if (rc > MaxThread)
        MaxThread = rc;

   }

   /*      Display how many threads were created         */

   printf("Number of threads = %d, Maximum thread ID = %d\n\n",
           NumThreads, MaxThread);

   --NumThreads;

   /* Let the threads begin execution and wait for them to complete  */

   DosPostEventSem( hev );

   for ( i=0; i<NumThreads; ++i) {
      DosWaitEventSem ( thread_info[i].hev, SEM_INDEFINITE_WAIT  );
      DosCloseEventSem( thread_info[i].hev );
   } /* endfor */

   /*  Close the semaphores  */

   DosCloseEventSem (hev);
   printf("\nDone!\n");
   return 0;
}

/*    "Hello world!" per thread routine.     */

void childcode( void * arg)
{
   TIB  *ptib;            /* pointer to a thread information block         */
   PIB  *ppib;            /* pointer to a process information block        */
   unsigned tid ;         /* thread id                                     */
   unsigned int i;        /* index for loop                                */
   THREAD_INFO * thread_info;

   thread_info = ( THREAD_INFO * ) arg;

   /* Get the addresses of the thread and process information blocks.      */

   DosGetInfoBlocks( &ptib, &ppib );

   tid = ( unsigned ) ptib->tib_ptib2->tib2_ultid ;

   /*   wait for the main routine to say "Go!"   */

   DosWaitEventSem ( hev, SEM_INDEFINITE_WAIT  );

   /*  print the message <arg> times              */
   /*  using DosSleep to delay thread execution   */

   for (i = 1; i <=  thread_info->count ; i++ ) {
    printf("Hello world from thread %i!\n",tid);
    DosSleep(0L);
   }

   /*  Let the main program know everything is done   */

   DosPostEventSem( thread_info->hev );

}
