1 /* Multi-thread searching. 2 Illustrates: thread cancellation, cleanup handlers. */ 3 4 #include <errno.h> 5 #include <stdio.h> 6 #include <unistd.h> 7 #include <stdlib.h> 8 #include <sys/types.h> 9 #include <pthread.h> 10 11 /* Defines the number of searching threads */ 12 #define NUM_THREADS 5 13 14 /* Function prototypes */ 15 void *search(void *); 16 void print_it(void *); 17 18 /* Global variables */ 19 pthread_t threads[NUM_THREADS]; 20 pthread_mutex_t lock; 21 int tries; 22 volatile int started; 23 24 int libc_ex3() 25 { 26 int i; 27 int pid; 28 29 /* create a number to search for */ 30 pid = getpid(); 31 printf("Searching for the number = %d...\n", pid); 32 33 /* Initialize the mutex lock */ 34 pthread_mutex_init(&lock, NULL); 35 36 /* Create the searching threads */ 37 for (started=0; started<NUM_THREADS; started++) 38 pthread_create(&threads[started], NULL, search, (void *)pid); 39 40 /* Wait for (join) all the searching threads */ 41 for (i=0; i<NUM_THREADS; i++) 42 pthread_join(threads[i], NULL); 43 44 printf("It took %d tries to find the number.\n", tries); 45 46 /* Exit the program */ 47 return 0; 48 } 49 #include <finsh.h> 50 FINSH_FUNCTION_EXPORT(libc_ex3, example 5 for libc); 51 52 /* This is the cleanup function that is called 53 when the threads are cancelled */ 54 55 void print_it(void *arg) 56 { 57 int *try = (int *) arg; 58 pthread_t tid; 59 60 /* Get the calling thread's ID */ 61 tid = pthread_self(); 62 63 /* Print where the thread was in its search when it was cancelled */ 64 printf("Thread %lx was canceled on its %d try.\n", tid, *try); 65 } 66 67 /* This is the search routine that is executed in each thread */ 68 69 void *search(void *arg) 70 { 71 int num = (int) arg; 72 int i, j, ntries; 73 pthread_t tid; 74 75 /* get the calling thread ID */ 76 tid = pthread_self(); 77 78 /* use the thread ID to set the seed for the random number generator */ 79 /* Since srand and rand are not thread-safe, serialize with lock */ 80 81 /* Try to lock the mutex lock -- 82 if locked, check to see if the thread has been cancelled 83 if not locked then continue */ 84 while (pthread_mutex_trylock(&lock) == EBUSY) 85 pthread_testcancel(); 86 87 srand((int)tid); 88 i = rand() & 0xFFFFFF; 89 pthread_mutex_unlock(&lock); 90 ntries = 0; 91 92 /* Set the cancellation parameters -- 93 - Enable thread cancellation 94 - Defer the action of the cancellation */ 95 96 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 97 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); 98 99 while (started < NUM_THREADS) 100 sched_yield (); 101 102 /* Push the cleanup routine (print_it) onto the thread 103 cleanup stack. This routine will be called when the 104 thread is cancelled. Also note that the pthread_cleanup_push 105 call must have a matching pthread_cleanup_pop call. The 106 push and pop calls MUST be at the same lexical level 107 within the code */ 108 109 /* Pass address of `ntries' since the current value of `ntries' is not 110 the one we want to use in the cleanup function */ 111 112 pthread_cleanup_push(print_it, (void *)&ntries); 113 114 /* Loop forever */ 115 while (1) { 116 i = (i + 1) & 0xFFFFFF; 117 ntries++; 118 119 /* Does the random number match the target number? */ 120 if (num == i) { 121 /* Try to lock the mutex lock -- 122 if locked, check to see if the thread has been cancelled 123 if not locked then continue */ 124 while (pthread_mutex_trylock(&lock) == EBUSY) 125 pthread_testcancel(); 126 127 /* Set the global variable for the number of tries */ 128 tries = ntries; 129 printf("Thread %lx found the number!\n", tid); 130 131 /* Cancel all the other threads */ 132 for (j=0; j<NUM_THREADS; j++) 133 if (threads[j] != tid) pthread_cancel(threads[j]); 134 135 /* Break out of the while loop */ 136 break; 137 } 138 139 /* Every 100 tries check to see if the thread has been cancelled. */ 140 if (ntries % 100 == 0) { 141 pthread_testcancel(); 142 } 143 } 144 145 /* The only way we can get here is when the thread breaks out 146 of the while loop. In this case the thread that makes it here 147 has found the number we are looking for and does not need to run 148 the thread cleanup function. This is why the pthread_cleanup_pop 149 function is called with a 0 argument; this will pop the cleanup 150 function off the stack without executing it */ 151 152 pthread_cleanup_pop(0); 153 return((void *)0); 154 } 155