Unlike processes, all threads in a single program share the same address space.This
means that if one thread modifies a location in memory (for instance, a global vari-able),the change is visible to all other threads.This allows multiple threads to operate
on the same data without the use interprocess communication mechanismsEach thread has its own call stack, however.This allows each thread to execute different
code and to call and return from subroutines in the usual way.
As in a single-threaded program, each invocation of a subroutine in each thread has its own set of
local variables, which are stored on the stack for that thread.Sometimes, however, it is desirable to duplicate a certain variable so that eachthread has a separate copy. GNU/Linux supports this by providing each thread with athread-specific data area.The variables stored in this area are duplicated for each thread,and each thread may modify its copy of a variable without affecting other threads.Because all threads share the same memory space, thread-specific data may not beaccessed using normal variable references. GNU/Linux provides special functions forsetting and retrieving values from the thread-specific data area。You may create as many thread-specific data items as you want, each of type void*.
Each item is referenced by a key.To create a new key, and thus a new data item foreach thread, use pthread_key_create.The first argument is a pointer to apthread_key_tvariable.That key value can be used by each thread to access its owncopy of the corresponding data item.The second argument to pthread_key_tis acleanup function. If you pass a function pointer here, GNU/Linux automatically callsthat function when each thread exits, passing the thread-specific value correspondingto that key.This is particularly handy because the cleanup function is called even if thethread is canceled at some arbitrary point in its execution. If the thread-specific valueis null, the thread cleanup function is not called. If you don’t need a cleanup function,you may pass null instead of a function pointer.After you’ve created a key, each thread can set its thread-specific value correspondingto that key by calling pthread_setspecific.The first argument is the key, and the
second is the void* thread-specific value to store.To retrieve a thread-specific dataitem, call pthread_getspecific, passing the key as its argument.Suppose, for instance, that your application divides a task among multiple threads.For audit purposes, each thread is to have a separate log file, in which progress messagesfor that thread’s tasks are recorded.The thread-specific data area is a convenient
place to store the file pointer for the log file for each individual thread.你想创建多少线程专有数据对象都可以;它们的类型都是void*。每个数据对象都通过
一个键值进行映射。要创建一个新键值从而为每个线程新创建一个数据对象,调用pthread_key_create函数。第一个参数是一个指向pthread_key_t类型变量的指针。新创建的键值将被保存在这个变量中。随后,这个键值可以被任意线程用于访问对应数据对象的属于自己的副本。传递给pthread_key_create的第二个参数是一个清理函数,如果你在这里传递一个函数指针,则GNU/Linux系统将在线程退出的时候以这个键值对应的数据对象为参数自动调用这个清理函数。清理函数非常有用,因为即使当线程在任何一个非特定运行时刻被取消,这个线程函数也会被保证调用。如果对应的数据对象是一个空指针,清理函数将不会被调用。如果你不需要调用清理函数,你可以在这里传递空指针。创建了键值之后,可以通过调用pthread_setspecific设定相应的线程专有数据值。第一个参数是键值,而第二个参数是一个指向要设置的数据的void*指针。以键值为参数调用pthread_getspecific可重新获取一个已经设置的线程专有数据。假设这样一种情况,你的程序将一个任务分解以供多个线程执行。为了进行审计,每个线程都将分配一个单独的日志文件,用于记录对应线程的任务完成进度。线程专有数据区是为每个单独线程保存对应的日志文件指针的最方便的地点。 Listing 4.7 shows how you might implement this.The mainfunction in this sampleprogram creates a key to store the thread-specific file pointer and then stores it inthread_log_key. Because this is a global variable, it is shared by all threads.When eachthread starts executing its thread function, it opens a log file and stores the file pointerunder that key. Later, any of these threads may call write_to_thread_logto write amessage to the thread-specific log file.That function retrieves the file pointer for thethread’s log file from thread-specific data and writes the message.Listing 4.7 (tsd.c) Per-Thread Log Files Implemented with Thread-Specific Data
#include <malloc.h>#include <pthread.h>#include <stdio.h>/* The key used to associate a log file pointer with each thread. */static pthread_key_t thread_log_key;/* Write MESSAGE to the log file for the current thread. */void write_to_thread_log (const char* message){ FILE* thread_log = (FILE*) pthread_getspecific (thread_log_key);fprintf (thread_log, “%s\n”, message);}/* Close the log file pointer THREAD_LOG. */void close_thread_log (void* thread_log){
fclose ((FILE*) thread_log);}void* thread_function (void* args){ char thread_log_filename[20];FILE* thread_log;/* Generate the filename for this thread’s log file. */sprintf (thread_log_filename, “thread%d.log”, (int) pthread_self ());/* Open the log file. */thread_log = fopen (thread_log_filename, “w”);/* Store the file pointer in thread-specific data under thread_log_key. */pthread_setspecific (thread_log_key, thread_log);write_to_thread_log (“Thread starting.”);/* Do work here... */return NULL;}int main (){ int i;pthread_t threads[5];/* Create a key to associate thread log file pointers inthread-specific data. Use close_thread_log to clean up the filepointers. */pthread_key_create (&thread_log_key, close_thread_log);/* Create threads to do the work. */for (i = 0; i < 5; ++i)pthread_create (&(threads[i]), NULL, thread_function, NULL);/* Wait for all threads to finish. */for (i = 0; i < 5; ++i)pthread_join (threads[i], NULL);return 0;}Observe that thread_functiondoes not need to close the log file.That’s because whenthe log file key was created,close_thread_logwas specified as the cleanup functionfor that key.Whenever a thread exits, GNU/Linux calls that function, passing thethread-specific value for the thread log key.This function takes care of closing thelog file.