Back to index

glibc  2.9
ex3.c
Go to the documentation of this file.
00001 /* Multi-thread searching.
00002    Illustrates: thread cancellation, cleanup handlers. */
00003 
00004 #include <errno.h>
00005 #include <stdio.h>
00006 #include <unistd.h>
00007 #include <stdlib.h>
00008 #include <sys/types.h>
00009 #include <pthread.h>
00010 
00011 /* Defines the number of searching threads */
00012 #define NUM_THREADS 5
00013 
00014 /* Function prototypes */
00015 void *search(void *);
00016 void print_it(void *);
00017 
00018 /* Global variables */
00019 pthread_t threads[NUM_THREADS];
00020 pthread_mutex_t lock;
00021 int tries;
00022 volatile int started;
00023 
00024 int main(int argc, char ** argv)
00025 {
00026   int i;
00027   int pid;
00028 
00029   /* create a number to search for */
00030   pid = getpid();
00031   printf("Searching for the number = %d...\n", pid);
00032 
00033   /* Initialize the mutex lock */
00034   pthread_mutex_init(&lock, NULL);
00035 
00036   /* Create the searching threads */
00037   for (started=0; started<NUM_THREADS; started++)
00038     pthread_create(&threads[started], NULL, search, (void *) (long int) pid);
00039 
00040   /* Wait for (join) all the searching threads */
00041   for (i=0; i<NUM_THREADS; i++)
00042     pthread_join(threads[i], NULL);
00043 
00044   printf("It took %d tries to find the number.\n", tries);
00045 
00046   /* Exit the program */
00047   return 0;
00048 }
00049 
00050 /* This is the cleanup function that is called
00051    when the threads are cancelled */
00052 
00053 void print_it(void *arg)
00054 {
00055   int *try = (int *) arg;
00056   pthread_t tid;
00057 
00058   /* Get the calling thread's ID */
00059   tid = pthread_self();
00060 
00061   /* Print where the thread was in its search when it was cancelled */
00062   printf("Thread %lx was canceled on its %d try.\n", tid, *try);
00063 }
00064 
00065 /* This is the search routine that is executed in each thread */
00066 
00067 void *search(void *arg)
00068 {
00069   int num = (long int) arg;
00070   int i, j, ntries;
00071   pthread_t tid;
00072 
00073   /* get the calling thread ID */
00074   tid = pthread_self();
00075 
00076   /* use the thread ID to set the seed for the random number generator */
00077   /* Since srand and rand are not thread-safe, serialize with lock */
00078 
00079   /* Try to lock the mutex lock --
00080      if locked, check to see if the thread has been cancelled
00081      if not locked then continue */
00082   while (pthread_mutex_trylock(&lock) == EBUSY)
00083     pthread_testcancel();
00084 
00085   srand((int)tid);
00086   i = rand() & 0xFFFFFF;
00087   pthread_mutex_unlock(&lock);
00088   ntries = 0;
00089 
00090   /* Set the cancellation parameters --
00091      - Enable thread cancellation
00092      - Defer the action of the cancellation */
00093 
00094   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
00095   pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
00096 
00097   while (started < NUM_THREADS)
00098     sched_yield ();
00099 
00100   /* Push the cleanup routine (print_it) onto the thread
00101      cleanup stack.  This routine will be called when the
00102      thread is cancelled.  Also note that the pthread_cleanup_push
00103      call must have a matching pthread_cleanup_pop call.  The
00104      push and pop calls MUST be at the same lexical level
00105      within the code */
00106 
00107   /* Pass address of `ntries' since the current value of `ntries' is not
00108      the one we want to use in the cleanup function */
00109 
00110   pthread_cleanup_push(print_it, (void *)&ntries);
00111 
00112   /* Loop forever */
00113   while (1) {
00114     i = (i + 1) & 0xFFFFFF;
00115     ntries++;
00116 
00117     /* Does the random number match the target number? */
00118     if (num == i) {
00119       /* Try to lock the mutex lock --
00120          if locked, check to see if the thread has been cancelled
00121          if not locked then continue */
00122       while (pthread_mutex_trylock(&lock) == EBUSY)
00123         pthread_testcancel();
00124 
00125       /* Set the global variable for the number of tries */
00126       tries = ntries;
00127       printf("Thread %lx found the number!\n", tid);
00128 
00129       /* Cancel all the other threads */
00130       for (j=0; j<NUM_THREADS; j++)
00131         if (threads[j] != tid) pthread_cancel(threads[j]);
00132 
00133       /* Break out of the while loop */
00134       break;
00135     }
00136 
00137     /* Every 100 tries check to see if the thread has been cancelled. */
00138     if (ntries % 100 == 0) {
00139       pthread_testcancel();
00140     }
00141   }
00142 
00143   /* The only way we can get here is when the thread breaks out
00144      of the while loop.  In this case the thread that makes it here
00145      has found the number we are looking for and does not need to run
00146      the thread cleanup function.  This is why the pthread_cleanup_pop
00147      function is called with a 0 argument; this will pop the cleanup
00148      function off the stack without executing it */
00149 
00150   pthread_cleanup_pop(0);
00151   return((void *)0);
00152 }