Basic Example
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 functionint main() {srand( (unsigned) time(NULL) ); pthread_t* Thread = new pthread_t[MAXTHREADS]; // thread handles int Buffer = 0; pthread_mutex_init( &cmutex, NULL); // initialize mutexfor (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.