The purpose of this lab is for you to gain mastery of thread synchronization. I have provided to you a tiny thread system called "tthreads" (gzipped tarball at tthreads.tgz).
To implement context switches, tthreads uses the "C" functions setjmp() and longjmp(), which are available under unix, cygwin, and most other runtime environments.
Setjmp() saves a process' registers in a "jmp_buf" structure. The return value of setjmp(jmp_buf) is zero when first called. Longjmp(jmp_buf, retval) restores those registers, effectively returning from setjmp() a second time, but this time setjmp() will return the value "retval" provided to longjmp(). Thus, a thread can save its context using setjmp, and another thread can "context switch" back to it using longjmp. A small demo program using setjmp is provided named "setJmpDemo.c". I encourage students to think about why a jmp_buf's saved context is invalid once the routine that called setjump() returns.
More info on longjmp/setjmp (thanks to Ryan Knotts).
Each tthreads thread is allocated approximately 64k of stack space by a functyion _makeThreads1() which calls _makeThreads2(). _makethreads2() saves its "context" using setjmp. To allocate a group of threads, these routines call each other in a mutually recursive fashion. Since a jmp_buf is invalid if the routine that called setjmp() returns, the pair of recursive makeThreads functions instead longjmp back to main()'s context.
ThreadTest recursively creates three threads, each which is assigned a workerNum in the range of (0..2). They iterate through a short loop 3*workerNum times, yielding the cpu (using the yield() function) before terminating.
I wrote a a simple mutex, its utilization is demonstrated in mutexDemo.c.
Your project is to implement a trivial producer-consumer system in tthreads with four producers and one consumer. Each producer will enqueue a sequence of 100 integer values (0..99) into a bounded production queue of capacity 10. The consumer will delete values from this queue, and when done, print their sum. To control access to the queues, you should utilize binary and counting semaphores. You are free to use the mutual exclusion algorithm in mutex.c/mutex.h as a binary semaphore, and to extend it to a counting semaphore.