<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> | |
<HTML> | |
<HEAD> | |
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8"> | |
<TITLE>PTHREAD_SPECIFIC(3) manual page</TITLE> | |
<META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.3 (Linux)"> | |
<META NAME="CREATED" CONTENT="20050504;18425400"> | |
<META NAME="CHANGED" CONTENT="20050509;18220200"> | |
<!-- manual page source format generated by PolyglotMan v3.2, --> | |
<!-- available at http://polyglotman.sourceforge.net/ --> | |
</HEAD> | |
<BODY LANG="en-GB" BGCOLOR="#ffffff" DIR="LTR"> | |
<H4>POSIX Threads for Windows – REFERENCE - <A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A></H4> | |
<P><A HREF="index.html">Reference Index</A></P> | |
<P><A HREF="#toc">Table of Contents</A></P> | |
<H2><A HREF="#toc0" NAME="sect0">Name</A></H2> | |
<P>pthread_key_create, pthread_key_delete, pthread_setspecific, | |
pthread_getspecific - management of thread-specific data | |
</P> | |
<H2><A HREF="#toc1" NAME="sect1">Synopsis</A></H2> | |
<P><B>#include <pthread.h></B> | |
</P> | |
<P><B>int pthread_key_create(pthread_key_t *</B><I>key</I><B>, void | |
(*</B><I>destr_function</I><B>) (void *));</B> | |
</P> | |
<P><B>int pthread_key_delete(pthread_key_t </B><I>key</I><B>);</B> | |
</P> | |
<P><B>int pthread_setspecific(pthread_key_t </B><I>key</I><B>, const | |
void *</B><I>pointer</I><B>);</B> | |
</P> | |
<P><B>void * pthread_getspecific(pthread_key_t </B><I>key</I><B>);</B> | |
</P> | |
<H2><A HREF="#toc2" NAME="sect2">Description</A></H2> | |
<P>Programs often need global or static variables that have different | |
values in different threads. Since threads share one memory space, | |
this cannot be achieved with regular variables. Thread-specific data | |
is the POSIX threads answer to this need. | |
</P> | |
<P>Each thread possesses a private memory block, the thread-specific | |
data area, or TSD area for short. This area is indexed by TSD keys. | |
The TSD area associates values of type <B>void *</B> to TSD keys. TSD | |
keys are common to all threads, but the value associated with a given | |
TSD key can be different in each thread. | |
</P> | |
<P>For concreteness, the TSD areas can be viewed as arrays of <B>void | |
*</B> pointers, TSD keys as integer indices into these arrays, and | |
the value of a TSD key as the value of the corresponding array | |
element in the calling thread. | |
</P> | |
<P>When a thread is created, its TSD area initially associates <B>NULL</B> | |
with all keys. | |
</P> | |
<P><B>pthread_key_create</B> allocates a new TSD key. The key is | |
stored in the location pointed to by <I>key</I>. There is a limit of | |
<B>PTHREAD_KEYS_MAX</B> on the number of keys allocated at a given | |
time. The value initially associated with the returned key is <B>NULL</B> | |
in all currently executing threads. | |
</P> | |
<P>The <I>destr_function</I> argument, if not <B>NULL</B>, specifies | |
a destructor function associated with the key. When a thread | |
terminates via <B>pthread_exit</B> or by cancellation, <I>destr_function</I> | |
is called with arguments the value associated with the key in that | |
thread. The <I>destr_function</I> is not called if that value is <B>NULL</B><SPAN STYLE="font-weight: medium"> | |
or the key has been deleted</SPAN>. The order in which destructor | |
functions are called at thread termination time is unspecified. | |
</P> | |
<P>Before the destructor function is called, the <B>NULL</B> value is | |
associated with the key in the current thread. A destructor function | |
might, however, re-associate non- <B>NULL</B> values to that key or | |
some other key. To deal with this, if after all the destructors have | |
been called for all non- <B>NULL</B> values, there are still some | |
non- <B>NULL</B> values with associated destructors, then the process | |
is repeated.</P> | |
<P><B>pthread_key_delete</B> deallocates a TSD key. It does not check | |
whether non- <B>NULL</B> values are associated with that key in the | |
currently executing threads, nor call the destructor function | |
associated with the key. | |
</P> | |
<P><B>pthread_setspecific</B> changes the value associated with <I>key</I> | |
in the calling thread, storing the given <I>pointer</I> instead. | |
</P> | |
<P><B>pthread_getspecific</B> returns the value currently associated | |
with <I>key</I> in the calling thread. | |
</P> | |
<P>The routines <B>pthread_setspecific</B>, <B>pthread_getspecific</B>, | |
and <B>pthread_key_delete</B> can be called from <I>destr_function</I> | |
targeting any valid key including the key on which <I>destr_function</I> | |
is currently operating. If <B>pthread_getspecific</B> is called on | |
the key whose thread specific data is being destroyed, the value NULL | |
is returned, unless <B>pthread_setspecific</B> was called previously | |
on that key from within <I>destr_function</I> to set the value to | |
non-NULL. For some implementations the effect of calling | |
<B>pthread_setspecific</B> from within <I>destr_function</I> can be | |
either memory leakage or infinite loops if <I>destr_function</I> has | |
already been called at least <B>PTHREAD_DESTRUCTOR_ITERATIONS</B> | |
times.</P> | |
<P STYLE="font-weight: medium"><B>Pthreads-w32</B> stops running key | |
<I>destr_function</I> routines after <B>PTHREAD_DESTRUCTOR_ITERATIONS</B> | |
iterations, even if some non- <B>NULL</B> values with associated | |
descriptors remain. If memory is allocated and associated with a key | |
from within <I>destr_function</I>, that memory may not be reclaimed | |
because that key's <I>destr_function</I>, may not run again.</P> | |
<H2><A HREF="#toc3" NAME="sect3">Return Value</A></H2> | |
<P><B>pthread_key_create</B>, <B>pthread_key_delete</B>, and | |
<B>pthread_setspecific</B> return 0 on success and a non-zero error | |
code on failure. If successful, <B>pthread_key_create</B> stores the | |
newly allocated key in the location pointed to by its <I>key</I> | |
argument. | |
</P> | |
<P><B>pthread_getspecific</B> returns the value associated with <I>key</I> | |
on success, and <B>NULL</B> on error. | |
</P> | |
<H2><A HREF="#toc4" NAME="sect4">Errors</A></H2> | |
<P><B>pthread_key_create</B> returns the following error code on | |
error: | |
</P> | |
<DL> | |
<DL> | |
<DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"><B>EAGAIN</B> | |
</DT></DL> | |
</DL> | |
<BLOCKQUOTE STYLE="margin-left: 5cm"> | |
<B>PTHREAD_KEYS_MAX</B> keys are already allocated | |
</BLOCKQUOTE> | |
<DL> | |
<DL> | |
<DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"><B>ENOMEM</B> | |
</DT></DL> | |
</DL> | |
<BLOCKQUOTE STYLE="margin-left: 5cm"> | |
Insufficient memory to allocate the key. | |
</BLOCKQUOTE> | |
<P><B>pthread_key_delete</B> and <B>pthread_setspecific</B> return | |
the following error code on error: | |
</P> | |
<DL> | |
<DL> | |
<DT STYLE="margin-right: 1cm; margin-bottom: 0.5cm"><B>EINVAL</B> | |
</DT><DD STYLE="margin-right: 1cm; margin-bottom: 0.5cm"> | |
<I>key</I> is not a valid, allocated TSD key | |
</DD></DL> | |
</DL> | |
<P> | |
<B>pthread_getspecific</B> returns <B>NULL</B> if <I>key</I> is not a | |
valid, allocated TSD key. | |
</P> | |
<H2><A HREF="#toc5" NAME="sect5">Author</A></H2> | |
<P>Xavier Leroy <Xavier.Leroy@inria.fr> | |
</P> | |
<P>Modified by Ross Johnson for use with <A HREF="http://sources.redhat.com/pthreads-win32">Pthreads-w32</A>.</P> | |
<H2><A HREF="#toc6" NAME="sect6">See Also</A></H2> | |
<P><A HREF="pthread_create.html">pthread_create(3)</A> , | |
<A HREF="pthread_exit.html">pthread_exit(3)</A> , | |
<A HREF="pthread_cancel.html">pthread_testcancel(3)</A> . | |
</P> | |
<H2><A HREF="#toc7" NAME="sect7">Example</A></H2> | |
<P>The following code fragment allocates a thread-specific array of | |
100 characters, with automatic reclamation at thread exit: | |
</P> | |
<BLOCKQUOTE><BR><BR> | |
</BLOCKQUOTE> | |
<PRE STYLE="margin-left: 1cm; margin-right: 1cm">/* Key for the thread-specific buffer */ | |
static pthread_key_t buffer_key; | |
/* Once-only initialisation of the key */ | |
static pthread_once_t buffer_key_once = PTHREAD_ONCE_INIT; | |
/* Allocate the thread-specific buffer */ | |
void buffer_alloc(void) | |
{ | |
pthread_once(&buffer_key_once, buffer_key_alloc); | |
pthread_setspecific(buffer_key, malloc(100)); | |
} | |
/* Return the thread-specific buffer */ | |
char * get_buffer(void) | |
{ | |
return (char *) pthread_getspecific(buffer_key); | |
} | |
/* Allocate the key */ | |
static void buffer_key_alloc() | |
{ | |
pthread_key_create(&buffer_key, buffer_destroy); | |
} | |
/* Free the thread-specific buffer */ | |
static void buffer_destroy(void * buf) | |
{ | |
free(buf); | |
}</PRE> | |
<HR> | |
<BLOCKQUOTE STYLE="margin-left: 0cm; margin-right: 0cm"><A NAME="toc"></A> | |
<B>Table of Contents</B></BLOCKQUOTE> | |
<UL> | |
<LI><BLOCKQUOTE STYLE="margin-bottom: 0cm"><A HREF="#sect0" NAME="toc0">Name</A> | |
</BLOCKQUOTE> | |
<LI><BLOCKQUOTE STYLE="margin-bottom: 0cm"><A HREF="#sect1" NAME="toc1">Synopsis</A> | |
</BLOCKQUOTE> | |
<LI><BLOCKQUOTE STYLE="margin-bottom: 0cm"><A HREF="#sect2" NAME="toc2">Description</A> | |
</BLOCKQUOTE> | |
<LI><BLOCKQUOTE STYLE="margin-bottom: 0cm"><A HREF="#sect3" NAME="toc3">Return | |
Value</A> | |
</BLOCKQUOTE> | |
<LI><BLOCKQUOTE STYLE="margin-bottom: 0cm"><A HREF="#sect4" NAME="toc4">Errors</A> | |
</BLOCKQUOTE> | |
<LI><BLOCKQUOTE STYLE="margin-bottom: 0cm"><A HREF="#sect5" NAME="toc5">Author</A> | |
</BLOCKQUOTE> | |
<LI><BLOCKQUOTE STYLE="margin-bottom: 0cm"><A HREF="#sect6" NAME="toc6">See | |
Also</A> | |
</BLOCKQUOTE> | |
<LI><BLOCKQUOTE><A HREF="#sect7" NAME="toc7">Example</A> | |
</BLOCKQUOTE> | |
</UL> | |
</BODY> | |
</HTML> |