ptMutex.c

/**
   @file      ptMutex.c
   @author    Mitch Richling <http://www.mitchr.me/>
   @Copyright Copyright 1998 by Mitch Richling.  All rights reserved.
   @brief     Basic pthread programming@EOL
   @Keywords  UNIX pthreads POSIX mutex
   @Std       ISOC POSIX UNIX98 BSD4.3 SYSV3

              This C program is intended to illustrate various
              concepts related to POSIX threads (pthreads) including
              simple mutex and condition variable use and basic thread
              creation and destruction.  Notable things not
              demonstrated are "Reader/Writer Locking", "Semaphores",
              "Cancellation", and "Scheduling".

   @Build     
              - MacOS X.2: c++ pthreads.cc
              - Linux (RH 7.3): c++ pthreads.cc -lpthread
              - Solaris 2.8: CC -lpthread -lrt pthreads.cc

   @Tested    
              - Solaris 2.8
              - MacOS X.2        
              - Linux (RH 7.3)

*/

#include <sys/types.h>          /* UNIX types      POSIX */
#include <stdio.h>              /* I/O lib         ISOC  */
#include <string.h>             /* Strings         ISOC  */
#include <dirent.h>             /* UNIX dirs       POSIX */
#include <errno.h>              /* error stf       POSIX */
#include <utime.h>              /* utime           POSIX */
#include <sys/stat.h>           /* UNIX stat       POSIX */
#include <time.h>               /* time            ISOC  */
#include <pthread.h>            /* threads         POSIX */
#include <sched.h>              /* threads         POSIX */
#include <stdlib.h>             /* Standard Lib    ISOC  */
#include <unistd.h>             /* UNIX std stf    POSIX */

/* Handy stuff for Multi-Threaded programs (in C only). */
#include "mtUtils.h"

/* *************************************************************************** */
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;

/* *************************************************************************** */

int main(int argc, char *argv[]);

void workThread1(void *reqArg);
void workThread2(void *reqArg);

/* *************************************************************************** */
/* This is where it starts. :) */
int main(int argc, char *argv[]) {
  pthread_t thread;
  int *anIntPtr;
  int i;
  int mstrThrdNumber=0;

  mtPrintf("main: startup.\n");

  /* Lock mutex1 -- everyone wants to lock this on startup. */
  mtPrintf("main: locking mutex1.\n");
  if(pthread_mutex_lock(&mutex1)) {
    mtPrintf("ERROR: pthread_mutex_lock() failed.\n");
    exit(1);
  } /* end if */
  mtPrintf("main: mutex1 locked.\n");

  mallocNsetInt(&anIntPtr, ++mstrThrdNumber);
  if(pthread_create(&thread, NULL, (PTHRFUNC*)workThread1, (void *)anIntPtr) != 0) {
    mtPrintf("ERROR: pthread_create() failed.\n");
    exit(1);
  } /* end if */

  mallocNsetInt(&anIntPtr, ++mstrThrdNumber);
  if(pthread_create(&thread, NULL, (PTHRFUNC*)workThread2, (void *)anIntPtr) != 0) {
    mtPrintf("ERROR: pthread_create() failed.\n");
    exit(1);
  } /* end if */

  for(i=0;i<4;i++) {
    mtPrintf("main: sleeping. (%d).\n", i);
    sleep(3);
  } /* end for */

  /* Unlock mutex1 -- everyone waiting to lock this one! */
  mtPrintf("main: unlocking mutex1.\n");
  if(pthread_mutex_unlock(&mutex1)) {
    mtPrintf("ERROR: pthread_mutex_lock() failed.\n");
    exit(1);
  } /* end if */
  mtPrintf("main: mutex1 unlocked.\n");

  for(i=0;i<10;i++) {
    mtPrintf("main: sleeping. (%d).\n", i);
    sleep(3);
  } /* end for */

  mtPrintf("main: shutdown\n");
  return (0);
} /* end func main */

/* *************************************************************************** */
void workThread1(void *reqArg) {

  /* Thread will never be "joined", so we detach it. */
  pthread_detach(pthread_self());

  mtPrintf("worker Type 1 thread %d startup.\n", *(int *)reqArg);

  mtPrintf("worker Type 1 thread %d locking mutex1.\n", *(int *)reqArg);
  if(pthread_mutex_lock(&mutex1)) {
    mtPrintf("ERROR: pthread_mutex_lock() failed.\n");
    exit(1);
  } /* end if */  
  mtPrintf("worker Type 1 thread %d mutex1 locked.\n", *(int *)reqArg);

  mtPrintf("worker Type 1 thread %d unlocking mutex1.\n", *(int *)reqArg);
  if(pthread_mutex_unlock(&mutex1)) {
    mtPrintf("ERROR: pthread_mutex_unlock() failed.\n");
    exit(1);
  } /* end if */  
  mtPrintf("worker Type 1 thread %d mutex1 unlocked.\n", *(int *)reqArg);


  mtPrintf("worker Type 1 thread %d shutdown.\n", *(int *)reqArg);

  /* The argument given to this thread was "malloced", so we free it now. */
  free(reqArg);
} /* end func workerThread */

/* *************************************************************************** */
void workThread2(void *reqArg) {
  int tryLockResult;

  /* Thread will never be "joined", so we detach it. */
  pthread_detach(pthread_self());

  mtPrintf("worker Type 2 thread %d startup.\n", *(int *)reqArg);

  mtPrintf("worker Type 2 thread %d locking mutex1.\n", *(int *)reqArg);
  while((tryLockResult = pthread_mutex_trylock(&mutex1))) {
    if(tryLockResult != EBUSY) {
      mtPrintf("ERROR: pthread_mutex_lock() failed.\n");
      exit(1);
    } /* end if */
    mtPrintf("worker Type 2 thread %d still trying to lock mutex1.\n", *(int *)reqArg);

    sleep(1);
  } /* end while */
  mtPrintf("worker Type 2 thread %d mutex1 locked.\n", *(int *)reqArg);

  mtPrintf("worker Type 2 thread %d unlocking mutex1.\n", *(int *)reqArg);
  if(pthread_mutex_unlock(&mutex1)) {
    mtPrintf("ERROR: pthread_mutex_unlock() failed.\n");
    exit(1);
  } /* end if */  
  mtPrintf("worker Type 2 thread %d mutex1 unlocked.\n", *(int *)reqArg);

  mtPrintf("worker Type 2 thread %d shutdown.\n", *(int *)reqArg);

  /* The argument given to this thread was "malloced", so we free it now. */
  free(reqArg);
} /* end func workerThread */

Generated by GNU Enscript 1.6.5.2.