| /* Multi-thread searching. |
| Illustrates: thread cancellation, cleanup handlers. */ |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <pthread.h> |
| |
| /* Defines the number of searching threads */ |
| #define NUM_THREADS 5 |
| |
| /* Function prototypes */ |
| void *search(void *); |
| void print_it(void *); |
| |
| /* Global variables */ |
| pthread_t threads[NUM_THREADS]; |
| pthread_mutex_t lock; |
| int tries; |
| volatile int started; |
| |
| int main(int argc, char ** argv) |
| { |
| unsigned long i; |
| unsigned long pid; |
| |
| /* create a number to search for */ |
| pid = getpid(); |
| printf("Searching for the number = %ld...\n", pid); |
| |
| /* Initialize the mutex lock */ |
| pthread_mutex_init(&lock, NULL); |
| |
| /* Create the searching threads */ |
| for (started=0; started<NUM_THREADS; started++) |
| pthread_create(&threads[started], NULL, search, (void *)pid); |
| |
| /* Wait for (join) all the searching threads */ |
| for (i=0; i<NUM_THREADS; i++) |
| pthread_join(threads[i], NULL); |
| |
| printf("It took %d tries to find the number.\n", tries); |
| |
| /* Exit the program */ |
| return 0; |
| } |
| |
| /* This is the cleanup function that is called |
| when the threads are cancelled */ |
| |
| void print_it(void *arg) |
| { |
| int *try = (int *) arg; |
| pthread_t tid; |
| |
| /* Get the calling thread's ID */ |
| tid = pthread_self(); |
| |
| /* Print where the thread was in its search when it was cancelled */ |
| printf("Thread %lx was canceled on its %d try.\n", tid, *try); |
| } |
| |
| /* This is the search routine that is executed in each thread */ |
| |
| void *search(void *arg) |
| { |
| unsigned long num = (unsigned long) arg; |
| unsigned long i, j, ntries; |
| pthread_t tid; |
| |
| /* get the calling thread ID */ |
| tid = pthread_self(); |
| |
| /* use the thread ID to set the seed for the random number generator */ |
| /* Since srand and rand are not thread-safe, serialize with lock */ |
| |
| /* Try to lock the mutex lock -- |
| if locked, check to see if the thread has been cancelled |
| if not locked then continue */ |
| while (pthread_mutex_trylock(&lock) == EBUSY) |
| pthread_testcancel(); |
| |
| srand((int)tid); |
| i = rand() & 0xFFFFFF; |
| pthread_mutex_unlock(&lock); |
| ntries = 0; |
| |
| /* Set the cancellation parameters -- |
| - Enable thread cancellation |
| - Defer the action of the cancellation */ |
| |
| pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
| pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); |
| |
| while (started < NUM_THREADS) |
| sched_yield (); |
| |
| /* Push the cleanup routine (print_it) onto the thread |
| cleanup stack. This routine will be called when the |
| thread is cancelled. Also note that the pthread_cleanup_push |
| call must have a matching pthread_cleanup_pop call. The |
| push and pop calls MUST be at the same lexical level |
| within the code */ |
| |
| /* Pass address of `ntries' since the current value of `ntries' is not |
| the one we want to use in the cleanup function */ |
| |
| pthread_cleanup_push(print_it, (void *)&ntries); |
| |
| /* Loop forever */ |
| while (1) { |
| i = (i + 1) & 0xFFFFFF; |
| ntries++; |
| |
| /* Does the random number match the target number? */ |
| if (num == i) { |
| /* Try to lock the mutex lock -- |
| if locked, check to see if the thread has been cancelled |
| if not locked then continue */ |
| while (pthread_mutex_trylock(&lock) == EBUSY) |
| pthread_testcancel(); |
| |
| /* Set the global variable for the number of tries */ |
| tries = ntries; |
| printf("Thread %lx found the number!\n", tid); |
| |
| /* Cancel all the other threads */ |
| for (j=0; j<NUM_THREADS; j++) |
| if (threads[j] != tid) pthread_cancel(threads[j]); |
| |
| /* Break out of the while loop */ |
| break; |
| } |
| |
| /* Every 100 tries check to see if the thread has been cancelled. */ |
| if (ntries % 100 == 0) { |
| pthread_testcancel(); |
| } |
| } |
| |
| /* The only way we can get here is when the thread breaks out |
| of the while loop. In this case the thread that makes it here |
| has found the number we are looking for and does not need to run |
| the thread cleanup function. This is why the pthread_cleanup_pop |
| function is called with a 0 argument; this will pop the cleanup |
| function off the stack without executing it */ |
| |
| pthread_cleanup_pop(0); |
| return((void *)0); |
| } |