亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 操作系統 > 正文

線程控制之線程私有數據

2024-06-28 13:28:12
字體:
來源:轉載
供稿:網友
線程控制之線程私有數據

線程私有數據(也稱線程特定數據)是存儲和查詢與某個線程相關的數據的一種機制。把這種數據稱為線程私有數據或線程特定數據的原因是:希望每個線程可以獨立地訪問數據副本,而不需要擔心與其他線程的同步訪問問題。

線程模型促進了進程中數據和屬性的共享,許多人在設計線程模型時會遇到各種麻煩。但在這樣的模型中,為什么還需要提出一些合適的用于阻止共享的接口呢?其中有兩個原因:

第一,有時候需要維護基于每個線程的數據。

采用線程私有數據的第二個原因是:它提供了讓基于進程的接口適應多線程環境的機制。一個很明顯的實例就是errno。回憶http://www.CUOXin.com/nufangrensheng/p/3495426.html中對errno的討論,(線程出現)以前的接口把errno定義為進程環境中全局可訪問的整數。系統調用和庫例程在調用或執行失敗時設置errno,把它作為操作失敗時的附屬結果。為了讓線程也能夠使用那些原本基于進程的的系統調用和庫例程,errno被重新定義為線程私有數據。這樣,一個線程做了設置errno的操作并不會影響進程中其他線程的errno的值。

進程中的所有線程都可以訪問進程的整個地址空間。除了使用寄存器以外,線程沒有辦法阻止其他線程訪問它的數據,線程私有數據也不例外。雖然底層的實現部分并不能阻止這種訪問能力,但管理線程私有數據的函數可以提高線程間的數據獨立性。

在分配線程私有數據之前,需要創建與該數據關聯的這個鍵將用于獲取對線程私有數據的訪問權。使用pthread_key_create創建一個鍵。

#include <pthread.h>int pthread_key_create(pthread_key_t *keyp,                       void (*destructor)(void *));返回值:若成功則返回0,否則返回錯誤編號

創建的鍵存放在keyp指向的內存單元,這個鍵可以被進程中的所有線程使用,但每個線程把這個鍵與不同的線程私有數據地址進行關聯(如何關聯???)。創建新鍵時,每個線程的數據地址設為null值。

除了創建鍵以外,pthread_key_create可以選擇為該鍵關聯析構函數,當線程退出時,如果數據地址已經被置為非null數值,那么析構函數就會被調用,它唯一的參數就是該數據地址。如果傳入的destructor參數為null,就表明沒有析構函數與鍵關聯。當線程調用pthread_exit或者線程執行返回,正常退出時,析構函數就會被調用,但如果線程調用了exit、_exit、_Exit、abort或出現其他非正常的退出時(關于正常退出與不正常退出:http://www.CUOXin.com/nufangrensheng/p/3509618.html),就不會調用析構函數。

線程通常使用malloc為線程私有數據分配內存空間,析構函數通常釋放已分配的內存。如果線程沒有釋放內存就退出了,那么這塊內存將會丟失,即線程所屬進程出現了內存泄漏。

線程可以為線程私有數據分配多個鍵,每個鍵都可以有一個析構函數與它關聯。各個鍵的析構函數可以互不相同,當然它們也可以使用相同的析構函數。每個操作系統在實現的時候可以對進程可分配的鍵的數量進行限制(回憶http://www.CUOXin.com/nufangrensheng/p/3522577.html中表12-1中的PTHREAD_KEYS_MAX)。

線程退出時,線程私有數據的析構函數將按照操作系統實現中定義的順序被調用。析構函數可能會調用另一個函數,該函數可能會創建新的線程私有數據而且把這個數據與當前的鍵關聯起來。當所有的析構函數都調用完成以后,系統會檢查是否還有非null的線程私有數據值與鍵關聯,如果有的話,再次調用析構函數。這個過程會一直重復直到線程所有的鍵都為null值線程私有數據,或者已經做了PTHREAD_DESTRUCTOR_ITERATIONS(http://www.CUOXin.com/nufangrensheng/p/3522577.html中表12-1)中定義的最大次數的嘗試。

對所有的線程,都可以通過調用pthread_key_delete來取消鍵與線程私有數據值之間的關聯關系。

#include <pthread.h>int pthread_key_delete(pthread_key_t *key);返回值:若成功則返回0,否則返回錯誤編號

注意,調用pthread_key_delete并不會激活與鍵關聯的析構函數。要釋放任何與鍵對應的線程私有數據值的內存空間,需要在應用程序中采取額外的步驟。

需要確保分配的鍵并不會由于在初始化階段的競爭而發生變動。下列代碼可以導致兩個線程都調用pthread_key_create:

void destructor(void *);pthread_key_t key;int init_done = 0;int threadfunc(void *arg){    if(!init_done)    {        init_done = 1;        err = pthread_key_create(&key, destructor);    }    ...}

有些線程可能看到某個鍵值,而其他的線程看到的可能是另一個不同的鍵值,這取決于系統是如何調度線程的,解決這種競爭的辦法是使用pthread_once。

#include <pthread.h>pthread_once_t initflag = PTHREAD_ONCE_INIT;int pthread_once(pthread_once_t *initflag, void (*initfn)(void));返回值:若成功則返回0,否則返回錯誤編號

initflag必須是一個非本地變量(即全局變量或靜態變量),而且必須初始化為PTHREAD_ONCE_INIT。

如果每個線程都調用pthread_once,系統就能保證初始化例程initfn只被調用一次,即在系統首次調用pthread_once時。創建鍵時避免出現競爭的一個恰當的方法可以描述如下:

void destructor(void *);pthread_key_t key;thread_once_t init_done = PTHREAD_ONCE_INIT;void thread_init(void){    err = pthread_key_create(&key, destructor);}intthreadfunc(void *arg){    pthread_once(&init_done, thread_init);    ...}

鍵一旦創建,就可以通過pthread_setspecific函數把鍵和線程私有數據關聯起來??梢酝ㄟ^pthread_getspecific函數獲得線程私有數據的地址。

#include <pthread.h>void *pthread_getspecific(pthread_key_t key);返回值:線程私有數據值;若沒有值與鍵關聯則返回NULLint pthread_setspecific(pthread_key_t key, const void *value);返回值:若成功則返回0,否則返回錯誤編號

如果沒有線程私有數據值與鍵關聯,pthread_getspecific將返回一個空指針,可以據此來確定是否需要調用pthread_setspecific。

實例

程序清單12-5 線程安全的getenv的兼容版本(使用線程私有數據來維護每個線程的數據緩沖區的副本,用于存放各自的返回字符串)

#include <limits.h>#include <string.h>#include <pthread.h>#include <stdlib.h>static pthread_key_t key;static pthread_once_t init_done = PTHREAD_ONCE_INIT;pthread_mutex_t env_mutex = PTHREAD_MUTEX_INITIALIZER;extern char **environ;static voidpthread_init(void){    pthread_key_create(&key, free);}char *getenv(const char *name){    int     i, len;    char     *envbuf;    pthread_once(&init_done, thread_init);    pthread_mutex_lock(&env_mutex);    envbuf = (char *)pthread_getspecific(key);    if(envbuf == NULL)    {        envbuf = malloc(ARG_MAX);        if(envbuf == NULL)        {            pthread_mutex_unlock(&env_mutex);            return(NULL);        }        pthread_setspecific(key, envbuf);    }    len = strlen(name);    for(i = 0; environ[i] != NULL; i++)    {        if((strncmp(name, environ[i], len) == 0) &&           (environ[i][len] == '='))        {            strcpy(envbuf, &environ[i][len+1]);            pthread_mutex_unlock(&env_mutex);            return(envbuf);        }    }        pthread_mutex_unlock(&env_mutex);    return(NULL);}

使用pthread_once來確保只為將要使用的線程私有數據創建了一個鍵。如果pthread_getspecific返回的是空指針,需要分配內存然后把鍵與該內存單元關聯,否則如果返回的不是空指針,就是用pthread_getspecific返回的內存單元。對析構函數,使用free來釋放之前由malloc分配的內存。只有當線程私有數據值為非null時,析構函數才會被調用。

注意,雖然這個版本的getenv是線程安全的,但它并不是異步-信號安全的。對信號處理程序而言,即使使用遞歸的互斥量,這個版本的getenv也不可能是可重入的,因為它調用了malloc,而malloc函數本身并不是異步-信號安全的。

本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關于本書可參考:http://www.apuebook.com/


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品视频免费在线观看| 国产欧美日韩综合精品| 久久在线免费观看视频| 精品视频在线观看日韩| 欧美国产日本高清在线| 精品久久久久久中文字幕大豆网| 日韩av电影院| 色老头一区二区三区在线观看| 日韩久久免费电影| 欧美一区三区三区高中清蜜桃| 日本高清不卡在线| 青青草原成人在线视频| 国产亚洲视频在线| 精品中文字幕久久久久久| 国产精品一区专区欧美日韩| 日韩有码在线播放| 中国china体内裑精亚洲片| 亚洲在线免费视频| 亚洲男人的天堂在线| 韩国v欧美v日本v亚洲| 91色精品视频在线| 热99在线视频| 久久69精品久久久久久国产越南| 国产精品久久电影观看| 日韩精品在线视频美女| 91精品国产亚洲| 中文字幕日韩欧美在线视频| 91亚洲精品视频| 黑人巨大精品欧美一区免费视频| 美女福利视频一区| 欧美亚洲伦理www| 色综合五月天导航| 欧美成人精品不卡视频在线观看| 亚洲精品大尺度| 欧美激情综合色综合啪啪五月| 亚洲欧美日韩在线高清直播| 亚洲a∨日韩av高清在线观看| 中文字幕久热精品视频在线| 国产一区红桃视频| 国内揄拍国内精品| 欧美精品在线第一页| 欧美激情喷水视频| 最新国产成人av网站网址麻豆| 欧美性videos高清精品| 欧美黑人一区二区三区| 欧美日韩亚洲激情| 亚洲激情视频在线| 日韩成人av网| 国产精品久久久久久久久影视| 欧美大片欧美激情性色a∨久久| 精品久久久久久久久中文字幕| 欧美一级淫片aaaaaaa视频| 精品中文字幕在线2019| 亚洲午夜激情免费视频| 97视频在线播放| 亚洲天堂av高清| 国产精品久久久久久久电影| 国产自摸综合网| 欧美激情第一页xxx| 96精品久久久久中文字幕| 久久在线免费观看视频| 成人精品久久av网站| 久久噜噜噜精品国产亚洲综合| 日韩在线精品视频| 欧美午夜久久久| 久久精品视频免费播放| 精品视频—区二区三区免费| 中文字幕在线视频日韩| 欧美大码xxxx| 国产啪精品视频| 亚洲精品美女久久久久| 欧美日韩在线视频观看| 成人av在线网址| 国产精品wwww| 亚洲色图35p| 97在线观看免费高清| 亚洲美女动态图120秒| 一区二区三区视频在线| 亚洲综合中文字幕68页| 91精品国产自产在线观看永久| 国产精品视频久久久| 不卡伊人av在线播放| 欧洲美女7788成人免费视频| 国产精品大片wwwwww| 91视频国产精品| 欧美亚洲成人精品| 国外成人性视频| 欧美视频在线看| 在线亚洲午夜片av大片| 亚洲美女性生活视频| 日韩免费视频在线观看| 超碰97人人做人人爱少妇| 欧洲成人午夜免费大片| 日韩成人中文电影| 日韩欧美国产视频| 91亚洲精品一区| 日韩精品免费在线观看| 欧美与欧洲交xxxx免费观看| 日韩一区二区三区国产| 日韩影视在线观看| 国产在线一区二区三区| 久久在精品线影院精品国产| 欧美激情中文网| 亚洲欧美在线磁力| 欧美午夜www高清视频| 亚洲美女av在线播放| 久久天天躁日日躁| 精品视频久久久久久| 精品视频久久久| 亚洲码在线观看| 欧美成人午夜激情在线| 欧美美女操人视频| 久久久爽爽爽美女图片| 亚洲乱码国产乱码精品精| 久久精品久久久久电影| 久久亚洲春色中文字幕| 日韩毛片在线看| 国产一区二区三区在线观看视频| 亚洲精品91美女久久久久久久| 亚洲国产成人精品女人久久久| 亚洲日韩中文字幕在线播放| 91欧美精品午夜性色福利在线| 日韩精品在线免费观看视频| 欧美在线一区二区三区四| 久久久精品久久久| 国产亚洲美女精品久久久| 欧美性生活大片免费观看网址| 国产精品无av码在线观看| 成人国内精品久久久久一区| 欧美性色视频在线| 欧美激情一二三| 欧美福利在线观看| 91国自产精品中文字幕亚洲| 日韩精品免费在线视频观看| 国产精品久久一区主播| 国产一区二区黄| 国产精品久久久一区| 国产精品国语对白| 欧美日韩国产一中文字不卡| 亚洲www永久成人夜色| 亚洲日韩中文字幕| 亚洲国产精品99久久| 国产精品日日摸夜夜添夜夜av| 91av在线免费观看| 国产精品99久久久久久白浆小说| 日韩在线视频中文字幕| 精品国偷自产在线| 国产91成人在在线播放| 欧美午夜电影在线| 91精品久久久久久久久久久久久久| 成人黄色中文字幕| 最近日韩中文字幕中文| 亚洲香蕉伊综合在人在线视看| 久久影视电视剧凤归四时歌| 欧美日韩另类视频| 午夜免费日韩视频| 日韩免费观看网站| 国产在线观看精品| 国产精品青青在线观看爽香蕉| 欧美激情一二区| 亚洲一区二区中文字幕| 久久综合久久88| 欧美性猛交xxxx偷拍洗澡| 国产精品久久久久久搜索|