線程中特有的線程存儲
下面說一下線程中特有的線程存儲, Thread Specific Data 。線程存儲有什麼用了?他是什麼意思了?大家都知道,在多線程程序中,所有線程共享程序中的變量。現在有一全局變量,所有線程都可以使用它,改變它的值。而如果每個線程希望能單獨擁有它,那麼就需要使用線程存儲了。表面上看起來這是一個全局變量,所有線程都可以使用它,而它的值在每一個線程中又是單獨存儲的。這就是線程存儲的意義。
下面說一下線程存儲的具體用法。
l 創建一個類型爲 pthread_key_t 類型的變量。
l 調用 pthread_key_create() 來創建該變量。該函數有兩個參數,第一個參數就是上面聲明的 pthread_key_t 變量,第二個參數是一個清理函數,用來在線程釋放該線程存儲的時候被調用。該函數指針可以設成 NULL ,這樣系統將調用默認的清理函數。
l 當線程中需要存儲特殊值的時候,可以調用 pthread_setspcific() 。該函數有兩個參數,第一個爲前面聲明的 pthread_key_t 變量,第二個爲 void* 變量,這樣你可以存儲任何類型的值。
l 如果需要取出所存儲的值,調用 pthread_getspecific() 。該函數的參數爲前面提到的 pthread_key_t 變量,該函數返回 void * 類型的值。
下面是前面提到的函數的原型:
int pthread_setspecific(pthread_key_t key, const void *value);
void *pthread_getspecific(pthread_key_t key);
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
下面是一個如何使用線程存儲的例子:
#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 in
thread-specific data. Use close_thread_log to clean up the file
pointers. */
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;
}
最後說一下線程的本質。
其實在Linux 中,新建的線程並不是在原先的進程中,而是系統通過一個系統調用clone() 。該系統copy 了一個和原先進程完全一樣的進程,並在這個進程中執行線程函數。不過這個copy 過程和fork 不一樣。copy 後的進程和原先的進程共享了所有的變量,運行環境。這樣,原先進程中的變量變動在copy 後的進程中便能體現出來。
下面說一下線程存儲的具體用法。
l 創建一個類型爲 pthread_key_t 類型的變量。
l 調用 pthread_key_create() 來創建該變量。該函數有兩個參數,第一個參數就是上面聲明的 pthread_key_t 變量,第二個參數是一個清理函數,用來在線程釋放該線程存儲的時候被調用。該函數指針可以設成 NULL ,這樣系統將調用默認的清理函數。
l 當線程中需要存儲特殊值的時候,可以調用 pthread_setspcific() 。該函數有兩個參數,第一個爲前面聲明的 pthread_key_t 變量,第二個爲 void* 變量,這樣你可以存儲任何類型的值。
l 如果需要取出所存儲的值,調用 pthread_getspecific() 。該函數的參數爲前面提到的 pthread_key_t 變量,該函數返回 void * 類型的值。
下面是前面提到的函數的原型:
int pthread_setspecific(pthread_key_t key, const void *value);
void *pthread_getspecific(pthread_key_t key);
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
下面是一個如何使用線程存儲的例子:
#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 in
thread-specific data. Use close_thread_log to clean up the file
pointers. */
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;
}
最後說一下線程的本質。
其實在Linux 中,新建的線程並不是在原先的進程中,而是系統通過一個系統調用clone() 。該系統copy 了一個和原先進程完全一樣的進程,並在這個進程中執行線程函數。不過這個copy 過程和fork 不一樣。copy 後的進程和原先的進程共享了所有的變量,運行環境。這樣,原先進程中的變量變動在copy 後的進程中便能體現出來。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.