CS 3204 pthread library mutex examples


Basic Example

  • The following short programs illustrate sharing of a simple counter.  Each spawned thread retrieves the current value of the counter, increments it, and stores the incremented value back into the counter, repeating that process 4 times.  Logically, the end result should be that the counter stores 4*(# of threads created).
  • The first version is unsynchronized and does not (usually) produce the correct result:

    #include <iostream>
    #include <iomanip>
    #include <ctime>
    #include <unistd.h>
    #include <new>
    using namespace std;

    const int MAXTHREADS = 2;

    void* F( void* arg);

    int main() {

       srand( (unsigned) time(NULL) );
       pthread_t* Thread = new pthread_t[MAXTHREADS];
       int Buffer = 0;

       for (int i = 0; i < MAXTHREADS; i++) {
          pthread_create( &Thread[i], NULL, F, (void*) &Buffer );
       }
       for (int i = 0; i < MAXTHREADS; i++) {
          pthread_join( Thread[i], NULL);
       }
       cout << "Counter equals: " << Buffer << endl;
       return 0;
    }

    void* F( void* arg) {

       int* pCounter = (int*) arg;
       for (int i = 1; i <= 4; i++) {
          int Value = *pCounter;
          cout << "Fetched " << Value << endl;
          sleep( rand() % 2 );
          Value++;
          *pCounter = Value;
       }
       pthread_exit(0);
    }

    The second version uses a pthread mutex object to synchronize the thread accesses:

    #include <iostream>
    #include <iomanip>
    #include <ctime>
    #include <unistd.h>
    #include <new>
    #include <pthread.h>
    using namespace std;
    const int MAXTHREADS = 2;
    pthread_mutex_t cmutex;  // create a mutex accessible to F()
    void* F( void* arg);     // thread function
    int main() {
       srand( (unsigned) time(NULL) );
       pthread_t* Thread = new pthread_t[MAXTHREADS];  // thread handles
       int Buffer = 0;
       pthread_mutex_init( &cmutex, NULL);           // initialize mutex
       for (int i = 0; i < MAXTHREADS; i++) {        // create threads
          pthread_create( &Thread[i], NULL, F, (void*) &Buffer );
       }	
       for (int i = 0; i < MAXTHREADS; i++) {        // join threads
          pthread_join( Thread[i], NULL);
       }
       pthread_mutex_destroy( &cmutex );             // destroy mutex
       cout << "Counter equals: " << Buffer << endl;
       return 0;
    }
    void* F( void* arg) {
       int* pCounter = (int*) arg;
       for (int i = 1; i <= 4; i++) {
          pthread_mutex_lock( &cmutex );             // request lock
          int Value = *pCounter;
          cout << "Fetched " << Value << endl;
          sleep( rand() % 2 );
          Value++;
          *pCounter = Value;
          pthread_mutex_unlock( &cmutex);           // release lock
       }
       pthread_exit(0);
    }

    Each thread requests a lock on the shared counter before performing any actions on it.  The thread retains the lock until its critical section actions are completed, and then the thread releases the lock.

     


    Note:  unless otherwise stated, the examples have been compiled and tested on Mandrake Linux 9.1 using gcc 3.2.2.  Some have also been tested using cygwin with gcc 3.3.1.