]>
Commit | Line | Data |
---|---|---|
5afdca00 UD |
1 | /* Multi-thread searching. |
2 | Illustrates: thread cancellation, cleanup handlers. */ | |
3 | ||
0302fece | 4 | #include <errno.h> |
5afdca00 UD |
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; | |
e3743e2f | 22 | volatile int started; |
5afdca00 | 23 | |
0302fece | 24 | int main(int argc, char ** argv) |
5afdca00 UD |
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 */ | |
0302fece | 34 | pthread_mutex_init(&lock, NULL); |
5afdca00 UD |
35 | |
36 | /* Create the searching threads */ | |
e3743e2f | 37 | for (started=0; started<NUM_THREADS; started++) |
59553897 | 38 | pthread_create(&threads[started], NULL, search, (void *) (long int) pid); |
5afdca00 UD |
39 | |
40 | /* Wait for (join) all the searching threads */ | |
0302fece | 41 | for (i=0; i<NUM_THREADS; i++) |
5afdca00 UD |
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 | ||
0302fece | 50 | /* This is the cleanup function that is called |
5afdca00 UD |
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 */ | |
0302fece | 62 | printf("Thread %lx was canceled on its %d try.\n", tid, *try); |
5afdca00 UD |
63 | } |
64 | ||
65 | /* This is the search routine that is executed in each thread */ | |
66 | ||
67 | void *search(void *arg) | |
68 | { | |
59553897 | 69 | int num = (long int) arg; |
5afdca00 UD |
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 */ | |
e3743e2f UD |
78 | |
79 | /* Try to lock the mutex lock -- | |
80 | if locked, check to see if the thread has been cancelled | |
81 | if not locked then continue */ | |
82 | while (pthread_mutex_trylock(&lock) == EBUSY) | |
83 | pthread_testcancel(); | |
84 | ||
5afdca00 UD |
85 | srand((int)tid); |
86 | i = rand() & 0xFFFFFF; | |
87 | pthread_mutex_unlock(&lock); | |
88 | ntries = 0; | |
89 | ||
90 | /* Set the cancellation parameters -- | |
0302fece | 91 | - Enable thread cancellation |
5afdca00 UD |
92 | - Defer the action of the cancellation */ |
93 | ||
94 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); | |
95 | pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); | |
96 | ||
e3743e2f UD |
97 | while (started < NUM_THREADS) |
98 | sched_yield (); | |
99 | ||
5afdca00 | 100 | /* Push the cleanup routine (print_it) onto the thread |
0302fece | 101 | cleanup stack. This routine will be called when the |
5afdca00 UD |
102 | thread is cancelled. Also note that the pthread_cleanup_push |
103 | call must have a matching pthread_cleanup_pop call. The | |
0302fece | 104 | push and pop calls MUST be at the same lexical level |
5afdca00 UD |
105 | within the code */ |
106 | ||
0302fece | 107 | /* Pass address of `ntries' since the current value of `ntries' is not |
5afdca00 UD |
108 | the one we want to use in the cleanup function */ |
109 | ||
110 | pthread_cleanup_push(print_it, (void *)&ntries); | |
111 | ||
112 | /* Loop forever */ | |
113 | while (1) { | |
114 | i = (i + 1) & 0xFFFFFF; | |
115 | ntries++; | |
116 | ||
117 | /* Does the random number match the target number? */ | |
118 | if (num == i) { | |
119 | /* Try to lock the mutex lock -- | |
120 | if locked, check to see if the thread has been cancelled | |
121 | if not locked then continue */ | |
122 | while (pthread_mutex_trylock(&lock) == EBUSY) | |
123 | pthread_testcancel(); | |
124 | ||
125 | /* Set the global variable for the number of tries */ | |
126 | tries = ntries; | |
127 | printf("Thread %lx found the number!\n", tid); | |
128 | ||
129 | /* Cancel all the other threads */ | |
0302fece | 130 | for (j=0; j<NUM_THREADS; j++) |
5afdca00 UD |
131 | if (threads[j] != tid) pthread_cancel(threads[j]); |
132 | ||
133 | /* Break out of the while loop */ | |
134 | break; | |
135 | } | |
136 | ||
137 | /* Every 100 tries check to see if the thread has been cancelled. */ | |
138 | if (ntries % 100 == 0) { | |
139 | pthread_testcancel(); | |
140 | } | |
141 | } | |
142 | ||
143 | /* The only way we can get here is when the thread breaks out | |
144 | of the while loop. In this case the thread that makes it here | |
145 | has found the number we are looking for and does not need to run | |
146 | the thread cleanup function. This is why the pthread_cleanup_pop | |
147 | function is called with a 0 argument; this will pop the cleanup | |
148 | function off the stack without executing it */ | |
149 | ||
150 | pthread_cleanup_pop(0); | |
151 | return((void *)0); | |
152 | } |