An optional destructor function, destructor, can be used to free stale storage. When a key has a non-NULL destructor function and the thread has a non-NULL value associated with that key, the destructor function is called with the current associated value when the thread exits. The order in which the destructor functions are called is unspecified.
Return Values
pthread_key_create() returns zero after completing successfully. Any other return value indicates that an error occurred. When any of the following conditions occur, pthread_key_create() fails and returns the corresponding value.
The key name space is exhausted.
Not enough virtual memory is available in this process to create a new key.
Delete the Thread-Specific Data Key
pthread_key_delete(3THR)
Use pthread_key_delete(3THR) to destroy an existing thread-specific data key. Any memory associated with the key can be freed because the key has been invalidated and will return an error if ever referenced. There is no comparable function in Solaris threads.
Prototype: int pthread_key_delete(pthread_key_t key); |
#include <pthread.h> pthread_key_t key; int ret; /* key previously created */ ret = pthread_key_delete(key); |
Once a key has been deleted, any reference to it with the pthread_setspecific() or pthread_getspecific() call yields undefined results.
It is the responsibility of the programmer to free any thread-specific resources before calling the delete function. This function does not invoke any of the destructors.
Return Values
pthread_key_delete() returns zero after completing successfully. Any other return value indicates that an error occurred. When the following condition occurs, pthread_key_create() fails and returns the corresponding value.
The key value is invalid.
Set Thread-Specific Data
pthread_setspecific(3THR)
Use pthread_setspecific(3THR) to set the thread-specific binding to the specified thread-specific data key.
Prototype: int pthread_setspecific(pthread_key_t key, const void *value); |
#include <pthread.h> pthread_key_t key; void *value; int ret; /* key previously created */ ret = pthread_setspecific(key, value); |
Return Values
pthread_setspecific() returns zero after completing successfully. Any other return value indicates that an error occurred. When any of the following conditions occur, pthread_setspecific() fails and returns the corresponding value.
Not enough virtual memory is available.
key is invalid.
Note - pthread_setspecific() does not free its storage. If a new binding is set, the existing binding must be freed; otherwise, a memory leak can occur.
Get Thread-Specific Data
pthread_getspecific(3THR)
Use pthread_getspecific(3THR) to get the calling thread's binding for key, and store it in the location pointed to by value.
Prototype: void *pthread_getspecific(pthread_key_t key); |
#include <pthread.h> pthread_key_t key; void *value; /* key previously created */ value = pthread_getspecific(key); |
Return Values
No errors are returned.
Global and Private Thread-Specific Data Example
Example 2-2 shows an excerpt from a multithreaded program. This code is executed by any number of threads, but it has references to two global variables, errno and mywindow, that really should be references to items private to each thread.
Example 2-2 Thread-Specific Data--Global but Private
body() { ... while (write(fd, buffer, size) == -1) { if (errno != EINTR) { fprintf(mywindow, "%s\n", strerror(errno)); exit(1); } } ... } |
References to errno should get the system error code from the routine called by this thread, not by some other thread. So, references to errno by one thread refer to a different storage location than references to errno by other threads.
The mywindow variable is intended to refer to a stdio stream connected to a window that is private to the referring thread. So, as with errno, references to mywindow by one thread should refer to a different storage location (and, ultimately, a different window) than references to mywindow by other threads. The only difference here is that the threads library takes care of errno, but the programmer must somehow make this work for mywindow.
The next example shows how the references to mywindow work. The preprocessor converts references to mywindow into invocations of the _mywindow() procedure.
This routine in turn invokes pthread_getspecific(), passing it the mywindow_key global variable (it really is a global variable) and an output parameter, win, that receives the identity of this thread's window.
Example 2-3 Turning Global References Into Private References
The mywin_key variable identifies a class of variables for which each thread has its own private copy; that is, these variables are thread-specific data. Each thread calls make_mywin() to initialize its window and to arrange for its instance of mywindow to refer to it.
Once this routine is called, the thread can safely refer to mywindow and, after _mywindow(), the thread gets the reference to its private window. So, references to mywindow behave as if they were direct references to data private to the thread.
Example 2-4 shows how to set this up.
Example 2-4 Initializing the Thread-Specific Data