xref: /nrf52832-nimble/rt-thread/examples/libc/ex3.c (revision 104654410c56c573564690304ae786df310c91fc)
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