-
Notifications
You must be signed in to change notification settings - Fork 53
/
tsd_destructor.c
118 lines (108 loc) · 3.31 KB
/
tsd_destructor.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
116
117
118
/*
* tsd_destructor.c
*
* Demonstrate use of thread-specific data destructors.
*/
#include <pthread.h>
#include "errors.h"
/*
* Structure used as value of thread-specific data key.
*/
typedef struct private_tag {
pthread_t thread_id;
char *string;
} private_t;
pthread_key_t identity_key; /* Thread-specific data key */
pthread_mutex_t identity_key_mutex = PTHREAD_MUTEX_INITIALIZER;
long identity_key_counter = 0;
/*
* This routine is called as each thread terminates with a value
* for the thread-specific data key. It keeps track of how many
* threads still have values, and deletes the key when there are
* no more references.
*/
void identity_key_destructor (void *value)
{
private_t *private = (private_t*)value;
int status;
printf ("thread \"%s\" exiting...\n", private->string);
free (value);
status = pthread_mutex_lock (&identity_key_mutex);
if (status != 0)
err_abort (status, "Lock key mutex");
identity_key_counter--;
if (identity_key_counter <= 0) {
status = pthread_key_delete (identity_key);
if (status != 0)
err_abort (status, "Delete key");
printf ("key deleted...\n");
}
status = pthread_mutex_unlock (&identity_key_mutex);
if (status != 0)
err_abort (status, "Unlock key mutex");
}
/*
* Helper routine to allocate a new value for thread-specific
* data key if the thread doesn't already have one.
*/
void *identity_key_get (void)
{
void *value;
int status;
value = pthread_getspecific (identity_key);
if (value == NULL) {
value = malloc (sizeof (private_t));
if (value == NULL)
errno_abort ("Allocate key value");
status = pthread_setspecific (identity_key, (void*)value);
if (status != 0)
err_abort (status, "Set TSD");
}
return value;
}
/*
* Thread start routine to use thread-specific data.
*/
void *thread_routine (void *arg)
{
private_t *value;
value = (private_t*)identity_key_get ();
value->thread_id = pthread_self ();
value->string = (char*)arg;
printf ("thread \"%s\" starting...\n", value->string);
sleep (2);
return NULL;
}
void main (int argc, char *argv[])
{
pthread_t thread_1, thread_2;
private_t *value;
int status;
/*
* Create the TSD key, and set the reference counter to
* the number of threads that will use it (two thread_routine
* threads plus main). This must be done before creating
* the threads! Otherwise, if one thread runs the key's
* destructor before any other thread uses the key, it will
* be deleted.
*
* Note that there's rarely any good reason to delete a
* thread-specific data key.
*/
status = pthread_key_create (&identity_key, identity_key_destructor);
if (status != 0)
err_abort (status, "Create key");
identity_key_counter = 3;
value = (private_t*)identity_key_get ();
value->thread_id = pthread_self ();
value->string = "Main thread";
status = pthread_create (&thread_1, NULL,
thread_routine, "Thread 1");
if (status != 0)
err_abort (status, "Create thread 1");
status = pthread_create (&thread_2, NULL,
thread_routine, "Thread 2");
if (status != 0)
err_abort (status, "Create thread 2");
pthread_exit (NULL);
}