46
47 pthread_cleanup_push (cleanup_handler, (void*)&control);
48
49 status = pthread_mutex_lock (&control.mutex);
50 if (status != 0)
51 err_abort (status, 'Mutex lock');
52 control.counter++;
53
54 while (control.busy) {
55 status = pthread_cond_wait (&control.cv, &control.mutex);
56 if (status != 0)
57 err_abort (status, 'Wait on condition');
58 }
59
60 pthread_cleanup_pop (1);
61 return NULL;
62 }
63
64 int main (int argc, char *argv[])
65 {
66 pthread_t thread_id[THREADS];
67 int count;
68 void *result;
69 int status;
70
71 for (count = 0; count < THREADS; count++) {
72 status = pthread_create (
73 &thread_id[count], NULL, thread_routine, NULL);
74 if (status != 0)
75 err_abort (status, 'Create thread');
76 }
77
78 sleep (2);
79
80 for (count = 0; count < THREADS; count++) {
81 status = pthread_cancel (thread_id[count]);
82 if (status != 0)
83 err_abort (status, 'Cancel thread'); 84
85 status = pthread_join (thread_id[count], &result);
86 if (status != 0)
87 err_abort (status, 'Join thread');
88 if (result == PTHREAD_CANCELED)
89 printf ('thread %d canceled
', count);
90 else
91 printf ('thread %d was not canceled
', count);
92 }
93 return 0;
If one of your threads creates a set of threads to 'subcontract' some function, say, a parallel arithmetic operation, and the 'contractor' is canceled while the function is in progress, you probably won't want to leave the subcontractor threads running. Instead, you could 'pass on' the cancellation to each subcontrator thread, letting them handle their own termination independently.
If you had originally intended to join with the subcontractors, remember that they will continue to consume some resources until they have been joined or detached. When the contractor thread cancels them, you should not delay cancellation by joining with the subcontractors. Instead, you can cancel each thread and immediately detach it using pthread_detach. The subcontractor resources can then be recycled immediately as they finish, while the contractor can wrap things up independently.
The following program, cancel_subcontract.c, shows one way to propagate cancellation to subcontractors.
9-12 The team_t
structure defines the state of the team of subcontractor threads. The join_i
member records the index of the last subcontractor with which the contractor had joined, so on cancellation from within pthread_join, it can cancel the threads it had not yet joined. The workers member is an array recording the thread identifiers of the subcontractor threads.
18-25 The subcontractor threads are started running the worker_routine function. This function loops until canceled, calling pthread_testcancel every 1000 iterations.
31-46 The cleanup function is established as the active cleanup handler within the contractor thread. When the contractor is canceled, cleanup iterates through the remaining (unjoined) subcontractors, cancelling and detaching each. Note that it does not join the subcontractors — in general, it is not a good idea to wait in a cleanup handler. The thread, after all, is expected to clean up and terminate, not to wait around for something to happen. But if your cleanup handler really needs to wait for something, don't be afraid, it will workjust fine.
53-76 The contractor thread is started running thread_routine. This function creates a set of subcontractors, then joins with each subcontractor. As it joins each thread, it records the current index within the workers array in the team_t member join_i. The cleanup handler is established with a pointer to the team structure so that it can determine the last offset and begin cancelling the remaining subcontractors.
78-104 The main program creates the contractor thread, running thread_routine, and then sleeps for five seconds. When it wakes up, it cancels the contractor thread, and waits for it to terminate.
¦ cancel_subcontract.c
1 #include <pthread.h>
2 #include 'errors.h' 3
4 #define THREADS 5
5
6 /*
7 * Structure that defines the threads in a 'team.'
8 */
9 typedef struct team_tag {
10 int join_i; /* join index */
11 pthread_t workers[THREADS]; /* thread identifiers */
12 } team_t;
13
14 /*
15 * Start routine for worker threads. They loop waiting for a
16 * cancellation request.
17 */
18 void *worker_routine (void *arg)
19 {
20 int counter;
21
22 for (counter = 0; ; counter++)
23 if ((counter % 1000) == 0)