/* Sample program demonstrating POSIX threads */ /* Topics covered: (1) Thread creation, parameter passing, attribute setting, thread joining (2) Using mutexes for critical sections (3) Using condition variables for synchronization */ #include #include #include /* Needed for strcpy() */ #include /* Needed for time() to seed the RNG */ #include /* Needed for sleep() and usleep() */ #include /* Needed for all pthread library calls */ /* Number of worker threads */ #define N 4 /* Data type for parameters to be passed to worker threads during start up */ typedef struct { int tno; char tname[5]; } tinfo; /* Array size */ #define S 100 /* Global arrays to be shared by all threads */ int A[S], C[S]; /* mutex for mutually exclusive updating of the arrays A[] and C[] */ pthread_mutex_t csmutex; /* mutex and condition variables for winding up */ pthread_mutex_t donemutex; pthread_cond_t donecond; int mdone = 0, wdone = 0; /* This is the main function for a worker thread */ /* A worker thread receives a number and a 4-letter name via targ */ void *tmain ( void *targ ) { /* Local variables are not shared with other threads */ int no, i; char name[5]; pthread_t tid; int count = 0, s, t; /* Retrieve my number and name from the parameter passed */ no = ((tinfo *)targ) -> tno; strcpy(name,((tinfo *)targ) -> tname); /* Retrieve my thread id */ tid = pthread_self(); printf("\t\t\t\t\t(%d,%s) [%lu] running\n", no, name, tid); while (1) { /* Check for termination condition */ pthread_mutex_lock(&donemutex); /* if the master thread is done */ if (mdone) { ++wdone; if (wdone < N) { /* Wait for signal from the last worker thread to finish */ /* This atomically unlocks the donemutex too */ if (wdone == 1) printf("\n"); printf("\t\t\t\t\t(%d,%s) going to wait\n", no, name); pthread_cond_wait(&donecond, &donemutex); /* When the signal is received, donemutex is again locked, and must be explicitly freed. */ } else { /* This is the last worker thread to finish. It must not itself wait on the condition variable. Instead, it should wake up the other worker threads waiting on the condition variable. */ printf("\n"); printf("\t\t\t\t\t(%d,%s) going to broadcast\n", no, name); printf("\n"); pthread_cond_broadcast(&donecond); /* Another option is to call pthread_cond_signal(&donecond) N - 1 times in order to signal the remaining threads one by one. */ } pthread_mutex_unlock(&donemutex); /* Explicitly exit */ printf("\t\t\t\t\t(%d,%s) exits with count = %d\n", no, name, count); pthread_exit(NULL); } /* The master thread is still sleeping, so I continue to work */ pthread_mutex_unlock(&donemutex); i = rand() % S; /* Entering critical section */ pthread_mutex_lock(&csmutex); /* Lock mutex for critical section */ s = A[i]; /* Read A[i] */ t = (s % 2 == 0) ? (s / 2) : (3 * s + 1); /* Compute new value */ A[i] = t; /* Update A[i] */ ++C[i]; /* Update C[i] */ pthread_mutex_unlock(&csmutex); /* Unlock mutex for critical section */ /* Leaving critical section */ /* Update and print local values only */ ++count; printf("\t\t\t\t\t(%d,%s) changes A[%2d] : %5d -> %5d\n", no,name,i,s,t); usleep(10); } } /* Initialize the arrays A[] and C[]. This is done before worker threads are created, so there is no necessity to use a mutex in this function. */ void init_arrays ( ) { int i; for (i=0; i