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