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

首頁 > 學院 > 開發設計 > 正文

多線程同步相關

2019-11-09 15:45:11
字體:
來源:轉載
供稿:網友

多線程的最大優點之一是數據的共享性,各個進程共享父進程處沿襲的數據段,可以方便的獲得、修改數據。但這也給多線程編程帶來了許多問題。 我們必須當心有多個不同的進程訪問相同的變量。許多函數是不可重入的,即同時不能運行一個函數的多個拷貝(除非使用不同的數據段)。 在函數中聲明的靜態變量常常帶來問題,函數的返回值也會有問題。因為如果返回的是函數內部靜態聲明的空間的地址, 則在一個線程調用該函數得到地址后使用該地址指向的數據時,別的線程可能調用此函數并修改了這一段數據。 為了保護變量,我們必須使用信號量、互斥等方法來保證我們對變量的正確使用。在Poxi標準中提供了互斥量,讀寫鎖,條件變量實現互斥訪問,下面意義探討。

互斥量

假設多個線程向同一個文件寫入數據,若對寫入的順序不加以管理和控制,那么最終生成的文件肯定是無法解析的。所以必須用互斥鎖來保證一段時間內只有一個線程在寫入文件,當一個線程寫入完成后再給下一線程寫入。

鎖的創建

鎖可以被動態或靜態創建,可以用宏PTHREAD_MUTEX_INITIALIZER來靜態的初始化鎖,采用這種方式比較容易理解,互斥鎖是pthread_mutex_t的結構體,而這個宏是一個結構常量,如下可以完成靜態的初始化:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

另外鎖可以用pthread_mutex_init函數動態的創建,函數原型如下:

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t * attr)

NULL參數表明使用默認屬性,通常使用默認屬性。

鎖的屬性

互斥鎖的范圍:可以指定是該進程與其他進程的同步還是同一進程內不同的線程之間的同步??梢栽O置為PTHREAD_PROCESS_SHARE和PTHREAD_PROCESS_PRIVATE。默認是后者,表示進程內使用鎖。#include <pthread.h>int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared);int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared); 互斥鎖的類型:PTHREAD_MUTEX_TIMED_NP,這是缺省值,也就是普通鎖。當一個線程加鎖以后,其余請求鎖的線程將形成一個等待隊列,并在解鎖后按優先級獲得鎖。這種鎖策略保證了資源分配的公平性。 PTHREAD_MUTEX_RECURSIVE_NP,嵌套鎖,允許同一個線程對同一個鎖成功獲得多次,并通過多次unlock解鎖。如果是不同線程請求,則在加鎖線程解鎖時重新競爭。 PTHREAD_MUTEX_ERRORCHECK_NP,檢錯鎖,如果同一個線程請求同一個鎖,則返回EDEADLK,否則與PTHREAD_MUTEX_TIMED_NP類型動作相同。這樣就保證當不允許多次加鎖時不會出現最簡單情況下的死鎖。 PTHREAD_MUTEX_ADAPTIVE_NP,適應鎖,動作最簡單的鎖類型,僅等待解鎖后重新競爭。int pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type)int pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type)

鎖操作

//上鎖int pthread_mutex_lock(pthread_mutex_t *mutex)int pthread_mutex_trylock(pthread_mutex_t *mutex)//解鎖int pthread_mutex_unlock(pthread_mutex_t *mutex)

pthread_mutex_trylock()語義與pthread_mutex_lock()類似,不同的是在鎖已經被占據時返回EBUSY而不是掛起等待。

鎖銷毀

int pthread_mutex_destory(pthread_mutex_t *mutex)

當鎖沒有被鎖定時??梢酝ㄟ^調用pthread_mutex_destory釋放鎖占用的資源。

使用示列

#include <pthread.h> #include <stdio.h> pthread_mutex_t mutex ; void *print_msg(void *arg){ int i=0; pthread_mutex_lock(&mutex); for(i=0;i<15;i++){ printf("output : %d/n",i); usleep(100); } pthread_mutex_unlock(&mutex); } int main(int argc,char** argv){ pthread_t id1; pthread_t id2; pthread_mutex_init(&mutex,NULL); pthread_create(&id1,NULL,print_msg,NULL); pthread_create(&id2,NULL,print_msg,NULL); pthread_join(id1,NULL); pthread_join(id2,NULL); pthread_mutex_destroy(&mutex); return 1; }

讀寫鎖

多個線程可以同時獲得讀鎖(Reader-Writer lock in read mode),但是只有一個線程能夠獲得寫鎖(Reader-writer lock in write mode)。

讀寫鎖總共有三種狀態: 1. 一個或者多個線程獲得讀鎖,其他線程無法獲得寫鎖 2. 一個線程獲得寫鎖,其他線程無法獲得讀鎖 3. 沒有線程獲得此讀寫鎖

#include <pthread.h>//初始化一個讀寫鎖,pthread_rwlockattr_t通常設為NULLint pthread_rwlock_init( pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr)//銷毀一個讀寫鎖int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);//獲取讀鎖int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);//獲取寫鎖int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);//讀寫解鎖int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

條件變量

適用的場景為條件滿足立刻被喚醒,否則掛起等待。條件需要被mutex保護。 條件變量類型為pthread_cond_t,必須被初始化為PTHREAD_COND_INITIALIZER,等價于調用pthread_cond_init(…, NULL)

#include <pthread.h>//初始化一個條件變量,和互斥鎖一樣我們可以用它來設置條件變量是進程內可用還是進程間可用,默認值是 PTHREAD_ PROCESS_PRIVATE,即此條件變量被同一進程內的各個線程使用。int pthread_cond_init( pthread_cond_t *restrict cond, const pthread_condxattr_t *restrict attr)//銷毀一個條件變量int pthread_cond_destroy(pthread_cond_t *cond);//等待條件發生int pthread_cond_wait( pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);int pthread_cond_timedwait( pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout);/*pthread_cond_timedwait類似,只是當等待超時的時候返回一個錯誤值ETIMEDOUT。超時的時間用timespec結構指定。struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */};注意timespec的時間是絕對時間而非相對時間,因此需要先調用gettimeofday函數獲得當前時間,再轉換成timespec結構,加上偏移量。*///條件滿足后喚醒等待的線程int pthread_cond_signal(pthread_cond_t *cond);int pthread_cond_broadcast(pthread_cond_t *cond);/*兩者的區別是前者會喚醒單個線程,而后者會喚醒多個線程。*/

示列

#include <stdio.h> #include <pthread.h> #include <unistd.h> pthread_mutex_t counter_lock; pthread_cond_t counter_nonzero; int counter = 0; int estatus = -1; void *decrement_counter(void *argv); void *increment_counter(void *argv); /* thd1啟動等待某個條件滿足后,才開始運行。 thd2當thd1運行的條件滿足后,開始喚醒thd1運行。*/ int main(int argc, char **argv) { printf("counter: %d/n", counter); pthread_t thd1, thd2; int ret; ret = pthread_create(&thd1, NULL, decrement_counter, NULL); if(ret){ perror("del:/n"); return 1; } ret = pthread_create(&thd2, NULL, increment_counter, NULL); if(ret){ perror("inc: /n"); return 1; } int counter = 0; while(counter != 2){ printf("counter(main): %d/n", counter); sleep(4); counter++; } return 0; } void *decrement_counter(void *argv) { pthread_mutex_lock(&counter_lock); printf("counter(decrement): %d decrement_counter lock! /n", counter); while(counter == 0) pthread_cond_wait(&counter_nonzero, &counter_lock); //進入阻塞(wait),等待喚醒信號 printf("counter--(before): %d/n", counter); counter--; //等待signal激活后再執行 printf("counter--(after): %d/n", counter); printf("decrement_counter will unlock! /n"); pthread_mutex_unlock(&counter_lock); return &estatus; } void *increment_counter(void *argv){ //模擬thd1比等待線程后啟動 sleep(1); pthread_mutex_lock(&counter_lock); printf("counter(increment): %d increment_counter lock!/n", counter); printf("counter++(before): %d/n", counter); counter++; printf("counter++(after): %d/n", counter); //thd1運行的條件滿足后,開始喚醒掛起的thd1 if(counter != 0) pthread_cond_signal(&counter_nonzero); printf("increment_counter will unlock!/n"); pthread_mutex_unlock(&counter_lock); return &estatus; }

gcc -g -pthread cond.c -lpthread -o test 運行test后,輸出如下:

counter: 0counter(main): 0counter(decrement): 0 decrement_counter lock! counter(increment): 0 increment_counter lock!counter++(before): 0counter++(after): 1increment_counter will unlock!counter--(before): 1counter--(after): 0decrement_counter will unlock! counter(main): 1

是不是覺得上面的輸出有點不可思議?明明decrement_counter lock為什么increment_counter lock還能成功。關鍵在于 pthread_cond_wait(&counter_nonzero, &counter_lock)在等待是,實際上已經將鎖unlock,并將線程掛起在等待隊列,等待喚醒。pthread_cond_signal(&counter_nonzero); 實際上會對對應mutex一個lock操作。

線程數據

在單線程的程序里,有兩種基本的數據:全局變量局部變量。但在多線程程序里,還有第三種數據類型:線程數據(TSD: Thread-Specific Data)。

它和全局變量很象,在線程內部,各個函數可以象使用全局變量一樣調用它,但它對線程外部的其它線程是不可見的。例如我們常見的變量errno,它返回標準的出錯信息。它顯然不能是一個局部變量,幾乎每個函數都應該可以調用它;但它又不能是一個全局變量,否則在 A線程里輸出的很可能是B線程的出錯信息。

要實現諸如此類的變量,我們就必須使用線程數據。我們為每個線程數據創建一個鍵,它和這個鍵相關聯,在各個線程里,都使用這個鍵來指代線程數據,但在不同的線程里,這個鍵代表的數據是不同的,在同一個線程里,它代表同樣的數據內容。

/*實現功能,創建5個線程,每個線程將日志記錄到thread%d.log日志文件中*/#include <malloc.h>#include <pthread.h>#include <stdio.h>static pthread_key_t thread_log_key;void write_to_thread_log (const char* message){ //從鍵讀取線程數據 FILE* thread_log = (FILE*) pthread_getspecific (thread_log_key); fprintf (thread_log, "%s/n", message); }void close_thread_log (void* thread_log){ fclose ((FILE*) thread_log);}void* thread_function (void* args){ char thread_log_filename[20]; FILE* thread_log; sprintf (thread_log_filename, "thread%d.log", (int) pthread_self ()); thread_log = fopen (thread_log_filename, "w+"); //為當前線程的鍵指定線程數據 pthread_setspecific (thread_log_key, thread_log); //記錄日志 write_to_thread_log ("Thread starting."); return NULL; }int main (){ int i; pthread_t threads[5]; //創建一個鍵,close_thread_log為線程退出時調用的析構函數 pthread_key_create (&thread_log_key, close_thread_log); for (i = 0; i < 5; ++i) pthread_create (&(threads[i]), NULL, thread_function, NULL); for (i = 0; i < 5; ++i) pthread_join (threads[i], NULL); //銷毀鍵 pthread_key_delete(thread_log_key); return 0;}
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久人人爽人人爽爽久久| www.国产精品一二区| www.欧美三级电影.com| 成人国产亚洲精品a区天堂华泰| 精品国产老师黑色丝袜高跟鞋| 亚洲第一精品久久忘忧草社区| 亚洲精品一区二区三区婷婷月| 国产99久久精品一区二区 夜夜躁日日躁| 国产欧美一区二区三区视频| 日韩久久精品成人| 日韩电影视频免费| 国产亚洲精品美女久久久久| 国产在线视频2019最新视频| 日韩电影大全免费观看2023年上| 欧美一级免费视频| 夜夜躁日日躁狠狠久久88av| 亚洲精品在线不卡| 亚洲成人激情小说| 中文字幕日韩有码| 福利二区91精品bt7086| 97精品国产97久久久久久免费| 国内精品中文字幕| 国产精品久久久久久久久男| 国产综合久久久久| 亚洲国产精彩中文乱码av在线播放| 亚洲色图国产精品| 亚洲人成电影网站色xx| 丝袜亚洲欧美日韩综合| 精品国产欧美成人夜夜嗨| 欧美影院在线播放| 欧美日本高清一区| 精品露脸国产偷人在视频| 成人精品视频久久久久| 亚洲xxxx视频| 中文字幕亚洲情99在线| xxav国产精品美女主播| 久久久久久久网站| 国产高清在线不卡| 精品视频偷偷看在线观看| 伊人一区二区三区久久精品| 亚洲福利在线观看| 亚洲美女av电影| 在线视频日韩精品| 国产福利精品av综合导导航| 这里精品视频免费| 国产精品91久久久久久| 国产精品国产三级国产专播精品人| 欧美色图在线视频| 国产午夜精品视频| 韩国美女主播一区| 日韩av中文字幕在线免费观看| 亚洲一区二区三区sesese| 一区二区欧美日韩视频| wwwwwwww亚洲| 亚洲免费人成在线视频观看| 欧美高清激情视频| 91久久国产精品91久久性色| 91久久久亚洲精品| 亚洲xxx自由成熟| 粗暴蹂躏中文一区二区三区| 亚洲资源在线看| 国产91色在线|| 久久91亚洲精品中文字幕奶水| 久久999免费视频| 久久久免费电影| 国产精品九九久久久久久久| 这里只有精品在线观看| 亚洲人成电影网| 性欧美长视频免费观看不卡| 成人h猎奇视频网站| 欧美在线观看网址综合| 国产精品第100页| 国产精品爽黄69天堂a| 亚洲九九九在线观看| 中文字幕久精品免费视频| 国产精品欧美激情| 亚洲亚裔videos黑人hd| 91免费人成网站在线观看18| 国产精品入口福利| 欧美第一页在线| 国产精品999999| 国产精品视频不卡| 国产精品夫妻激情| 亚洲国产精品美女| 欧美性猛交99久久久久99按摩| 国产精品吊钟奶在线| 亚洲第一网站男人都懂| 97在线视频免费观看| 一区二区三区国产在线观看| 精品一区二区三区四区在线| 亚洲成人黄色网址| 伊人一区二区三区久久精品| 成人写真视频福利网| 日韩成人在线观看| 日韩av资源在线播放| 92福利视频午夜1000合集在线观看| 中文字幕免费国产精品| 清纯唯美亚洲激情| 色黄久久久久久| 久久久久久久久久av| 狠狠躁夜夜躁人人爽天天天天97| 国产一区二区日韩精品欧美精品| 国产精品久久久久久亚洲调教| 国产一区二区三区日韩欧美| 色综合亚洲精品激情狠狠| 国产视频福利一区| 国语自产偷拍精品视频偷| 日韩在线激情视频| 久久久av亚洲男天堂| 日韩专区中文字幕| 中文字幕日韩视频| 69视频在线免费观看| 亚洲精品一区中文字幕乱码| 欧美乱妇高清无乱码| 26uuu日韩精品一区二区| 91av在线免费观看视频| 欧美大片在线看| 久久网福利资源网站| 欧美精品久久一区二区| 国产精品久久久久国产a级| 国产91在线播放精品91| 中文字幕在线精品| 一区二区三区视频免费| 日韩最新av在线| 欧美性xxxx在线播放| 国产一区二区三区在线观看视频| 成人免费视频网址| 日本道色综合久久影院| 国产精品视频一区二区三区四| 狠狠色香婷婷久久亚洲精品| 国产美女直播视频一区| 久久人人爽人人爽人人片av高清| 亚洲最大的免费| 亚洲理论电影网| 丝袜亚洲欧美日韩综合| 成人高清视频观看www| 伊人伊成久久人综合网小说| 欧美亚洲日本网站| 欧美日韩亚洲一区二| 欧美性xxxx极品高清hd直播| 亚洲已满18点击进入在线看片| 国产精品日日做人人爱| 午夜精品福利视频| 亚洲精品女av网站| 亚洲欧美制服第一页| 欧美精品电影免费在线观看| 68精品久久久久久欧美| 亚洲毛茸茸少妇高潮呻吟| 欧美专区福利在线| 国产欧美一区二区三区四区| 亚洲精品美女在线观看播放| 欧美在线免费观看| 久久久久国色av免费观看性色| 亚洲精品国产拍免费91在线| 亚洲欧美一区二区三区在线| 欧美理论电影网| 黄色成人在线播放| 综合国产在线观看| 欧美理论电影在线播放| 亚洲激情中文字幕| 日韩在线精品一区| 日韩中文字幕在线视频播放| 成人h猎奇视频网站| 国产999在线|