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