/* pthreadex.c */ /* This version is used to test Lamport's algorithm for N threads */ /* To compile (on a Solaris == SunOS 5.x machine ) */ /* cc pthreadex.c -lpthread -lrt */ /* To run */ /* a.out 100 */ #include #include #include #include #define MAX_THREADS 16 /* Maximum possible number of threads */ #define NUM_THREADS 8 /* Number of threads to us in this run */ pthread_t td[MAX_THREADS]; /* Thread descriptors for the new threads */ pthread_attr_t attr; pthread_mutex_t t_mtx = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t t_cond = PTHREAD_COND_INITIALIZER; volatile int shared = 0; /* The shared variable being updated */ int loopcount = 100000; /* Default value for increment count */ FILE *io; #ifdef SOLARIS #define sched_yield thr_yield #endif /* This program as currently configured will give the wrong */ /* answers because of destructive competition for the shared */ /* file test.dat... One way to make it get the right answer */ /* is to uncomment the following line: */ /* #define SAFE 1 */ /* If you do this, the system provided routines */ /* pthread_mutex_lock() and pthread_mutex_unlock() */ /* will provide the required functionality "automagically" */ /* Since we don't like automagic stuff in this course you */ /* will not be using pthread_mutex_lock() in your solution. */ #if 1 /**/ /* Lamport's algorithm REQUIRE's knowledge */ /* of the number of threads in use. This function */ /* is used to set that number . */ void lamp_init( int num_threads) { return; } /**/ /* This function is called prior to entering the critical */ /* section. Threads that call lamp_lock() with the C.S. */ /* is occupied will busy-wait (loop) until it is their */ /* turn to enter the C.S. */ void lamp_lock( int tid) /* Thread id */ { #ifdef SAFE pthread_mutex_lock(&t_mtx); #endif } /**/ /* This function is called when a thread exits the critical */ /* section. */ void lamp_unlock( int tid) /* Thread id */ { #ifdef SAFE pthread_mutex_unlock(&t_mtx); #endif } #endif /* We will run instances of this function as separate threads */ /* The function reads in a value from a file, adds 1 to the */ /* value and then writes it back out to the file. */ /* Thus, if proper mutex is enforced, at the end of the run */ /* the value in the file will be NUM_THREADS * loopcount */ /* Don't use a huge value for loopcount or the program can */ /* (literally) take hours to run. */ void *xthread( void *parm) /* Logical thread id.. values are 0, 1, 2,... */ { int i; int id; int local; FILE *work; id = (int)parm; printf("Starting thread %d \n", id); for (i = 0; i < loopcount; i++) { lamp_lock(id); /* Read in an int from the shared file test.dat */ /* If multiple threads are allowed in this code */ /* destruction of the file is likely! */ work = fopen("test.dat", "r"); if (fscanf(work, "%d", &local) != 1) { printf("YEOW: my input file is trashed \n"); printf("Thread %d exiting \n", id); perror("Failure was"); fclose(work); pthread_exit(0); } fclose(work); /* Yield to competing threads heres... This yield makes */ /* it more likely that if our mutex mechanism is broken, */ /* then we will find out about it. */ sched_yield(); /* Increment the value and write it back out. */ local += 1; work = fopen("test.dat", "w"); fprintf(work, "%d", local); fclose(work); /* Finally unlock the mutex */ lamp_unlock(id); } pthread_exit((void *)0); } int main( int argc, char **argv) { int tid; int pri; int stat; int tstatus; /* Tell the Lamport module how many threads we intend to run */ lamp_init(NUM_THREADS); /* Initialize the value in the shared output file */ io = fopen("test.dat", "w"); fprintf(io, "%12d", 0); fclose(io); /* Override loop count if user supplied one */ if (argc > 1) sscanf(argv[1], "%d", &loopcount); pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); /* Create the threads */ for (tid = 0; tid < NUM_THREADS; tid++) { pthread_create(&td[tid], &attr, (void *)xthread, (void *)tid); } /* Wait for all to terminate */ for (tid = 0; tid < NUM_THREADS; tid++) { stat = pthread_join(td[tid], NULL); printf("Thread %d done \n", tid); } printf("Made it out \n"); }