forked from hailinzeng/Programming-POSIX-Threads
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cancel_subcontract.c
115 lines (102 loc) · 3.13 KB
/
cancel_subcontract.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
* cancel_subcontract.c
*
* Demonstrate how a thread can handle cancellation and in turn
* cancel a set of worker ("subcontractor") threads.
*
* Special notes: On a Solaris 2.5 uniprocessor, this test will
* hang unless an LWP is created for each worker thread by
* calling thr_setconcurrency(), because threads are not
* timesliced.
*/
#include <pthread.h>
#include "errors.h"
#define THREADS 5
/*
* Structure that defines the threads in a "team".
*/
typedef struct team_tag {
int join_i; /* join index */
pthread_t workers[THREADS]; /* thread identifiers */
} team_t;
/*
* Start routine for worker threads. They loop waiting for a
* cancellation request.
*/
void *worker_routine (void *arg)
{
int counter;
for (counter = 0; ; counter++)
if ((counter % 1000) == 0)
pthread_testcancel ();
}
/*
* Cancellation cleanup handler for the contractor thread. It
* will cancel and detach each worker in the team.
*/
void cleanup (void *arg)
{
team_t *team = (team_t *)arg;
int count, status;
for (count = team->join_i; count < THREADS; count++) {
status = pthread_cancel (team->workers[count]);
if (status != 0)
err_abort (status, "Cancel worker");
status = pthread_detach (team->workers[count]);
if (status != 0)
err_abort (status, "Detach worker");
printf ("Cleanup: cancelled %d\n", count);
}
}
/*
* Thread start routine for the contractor. It creates a team of
* worker threads, and then joins with them. When cancelled, the
* cleanup handler will cancel and detach the remaining threads.
*/
void *thread_routine (void *arg)
{
team_t team; /* team info */
int count;
void *result; /* Return status */
int status;
for (count = 0; count < THREADS; count++) {
status = pthread_create (
&team.workers[count], NULL, worker_routine, NULL);
if (status != 0)
err_abort (status, "Create worker");
}
pthread_cleanup_push (cleanup, (void*)&team);
for (team.join_i = 0; team.join_i < THREADS; team.join_i++) {
status = pthread_join (team.workers[team.join_i], &result);
if (status != 0)
err_abort (status, "Join worker");
}
pthread_cleanup_pop (0);
return NULL;
}
int main (int argc, char *argv[])
{
pthread_t thread_id;
int status;
#ifdef sun
/*
* On Solaris 2.5, threads are not timesliced. To ensure
* that our threads can run concurrently, we need to
* increase the concurrency level to at least 2 plus THREADS
* (the number of workers).
*/
DPRINTF (("Setting concurrency level to %d\n", THREADS+2));
thr_setconcurrency (THREADS+2);
#endif
status = pthread_create (&thread_id, NULL, thread_routine, NULL);
if (status != 0)
err_abort (status, "Create team");
sleep (5);
printf ("Cancelling...\n");
status = pthread_cancel (thread_id);
if (status != 0)
err_abort (status, "Cancel team");
status = pthread_join (thread_id, NULL);
if (status != 0)
err_abort (status, "Join team");
}