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

首頁 > 服務器 > Linux服務器 > 正文

詳解Linux多線程使用信號量同步

2024-09-05 23:02:42
字體:
來源:轉載
供稿:網友

信號量、同步這些名詞在進程間通信時就已經說過,在這里它們的意思是相同的,只不過是同步的對象不同而已。但是下面介紹的信號量的接口是用于線程的信號量,注意不要跟用于進程間通信的信號量混淆。

一、什么是信號量

線程的信號量與進程間通信中使用的信號量的概念是一樣,它是一種特殊的變量,它可以被增加或減少,但對其的關鍵訪問被保證是原子操作。如果一個程序中有多個線程試圖改變一個信號量的值,系統將保證所有的操作都將依次進行。

而只有0和1兩種取值的信號量叫做二進制信號量,在這里將重點介紹。而信號量一般常用于保護一段代碼,使其每次只被一個執行線程運行。我們可以使用二進制信號量來完成這個工作。

二、信號量的接口和使用

信號量的函數都以sem_開頭,線程中使用的基本信號量函數有4個,它們都聲明在頭文件semaphore.h中。

1、sem_init函數

該函數用于創建信號量,其原型如下:

int sem_init(sem_t *sem, int pshared, unsigned int value); 

該函數初始化由sem指向的信號對象,設置它的共享選項,并給它一個初始的整數值。pshared控制信號量的類型,如果其值為0,就表示這個信號量是當前進程的局部信號量,否則信號量就可以在多個進程之間共享,value為sem的初始值。調用成功時返回0,失敗返回-1.

2、sem_wait函數

該函數用于以原子操作的方式將信號量的值減1。原子操作就是,如果兩個線程企圖同時給一個信號量加1或減1,它們之間不會互相干擾。它的原型如下:

int sem_wait(sem_t *sem); 

sem指向的對象是由sem_init調用初始化的信號量。調用成功時返回0,失敗返回-1.

3、sem_post函數

該函數用于以原子操作的方式將信號量的值加1。它的原型如下:

int sem_post(sem_t *sem); 

與sem_wait一樣,sem指向的對象是由sem_init調用初始化的信號量。調用成功時返回0,失敗返回-1.

4、sem_destroy函數

該函數用于對用完的信號量的清理。它的原型如下:

int sem_destroy(sem_t *sem); 

成功時返回0,失敗時返回-1.

三、使用信號量同步線程

下面以一個簡單的多線程程序來說明如何使用信號量進行線程同步。在主線程中,我們創建子線程,并把數組msg作為參數傳遞給子線程,然后主線程等待直到有文本輸入,然后調用sem_post來增加信號量的值,這樣就會立刻使子線程從sem_wait的等待中返回并開始執行。線程函數在把字符串的小寫字母變成大寫并統計輸入的字符數量之后,它再次調用sem_wait并再次被阻塞,直到主線程再次調用sem_post增加信號量的值。

#include <unistd.h> #include <pthread.h> #include <semaphore.h> #include <stdlib.h> #include <stdio.h> #include <string.h>  //線程函數 void *thread_func(void *msg); sem_t sem;//信號量  #define MSG_SIZE 512  int main() {   int res = -1;   pthread_t thread;   void *thread_result = NULL;   char msg[MSG_SIZE];   //初始化信號量,其初值為0   res = sem_init(&sem, 0, 0);   if(res == -1)   {     perror("semaphore intitialization failed/n");     exit(EXIT_FAILURE);   }   //創建線程,并把msg作為線程函數的參數   res = pthread_create(&thread, NULL, thread_func, msg);   if(res != 0)   {     perror("pthread_create failed/n");     exit(EXIT_FAILURE);   }   //輸入信息,以輸入end結束,由于fgets會把回車(/n)也讀入,所以判斷時就變成了“end/n”   printf("Input some text. Enter 'end'to finish.../n");   while(strcmp("end/n", msg) != 0)   {     fgets(msg, MSG_SIZE, stdin);     //把信號量加1     sem_post(&sem);   }    printf("Waiting for thread to finish.../n");   //等待子線程結束   res = pthread_join(thread, &thread_result);   if(res != 0)   {     perror("pthread_join failed/n");     exit(EXIT_FAILURE);   }   printf("Thread joined/n");   //清理信號量   sem_destroy(&sem);   exit(EXIT_SUCCESS); }  void* thread_func(void *msg) {   //把信號量減1   sem_wait(&sem);   char *ptr = msg;   while(strcmp("end/n", msg) != 0)   {     int i = 0;     //把小寫字母變成大寫     for(; ptr[i] != '/0'; ++i)     {       if(ptr[i] >= 'a' && ptr[i] <= 'z')       {         ptr[i] -= 'a' - 'A';       }     }     printf("You input %d characters/n", i-1);     printf("To Uppercase: %s/n", ptr);     //把信號量減1     sem_wait(&sem);   }   //退出線程   pthread_exit(NULL); } 

運行結果如下:

linux,多線程,信號量,信號量實現進程同步,同步信號量

從運行的結果來看,這個程序的確是同時在運行兩個線程,一個控制輸入,另一個控制處理統計和輸出。

四、分析此信號量同步程序的缺陷

但是這個程序有一點點的小問題,就是這個程序依賴接收文本輸入的時間足夠長,這樣子線程才有足夠的時間在主線程還未準備好給它更多的單詞去處理和統計之前處理和統計出工作區中字符的個數。所以當我們連續快速地給它兩組不同的單詞去統計時,子線程就沒有足夠的時間支執行,但是信號量已被增加不止一次,所以字符統計線程(子線程)就會反復處理和統計字符數目,并減少信號量的值,直到它再次變成0為止。

為了更加清楚地說明上面所說的情況,修改主線程的while循環中的代碼,如下:

printf("Input some text. Enter 'end'to finish.../n"); while(strcmp("end/n", msg) != 0) {   if(strncmp("TEST", msg, 4) == 0)   {     strcpy(msg, "copy_data/n");     sem_post(&sem);   }   fgets(msg, MSG_SIZE, stdin);   //把信號量加1   sem_post(&sem); } 

重新編譯程序,此時運行結果如下:

linux,多線程,信號量,信號量實現進程同步,同步信號量

當我們輸入TEST時,主線程向子線程提供了兩個輸入,一個是來自鍵盤的輸入,一個來自主線程復數據到msg中,然后從運行結果可以看出,運行出現了異常,沒有處理和統計從鍵盤輸入TEST的字符串而卻對復制的數據作了兩次處理。原因如上面所述。

五、解決此缺陷的方法

解決方法有兩個,一個就是再增加一個信號量,讓主線程等到子線程處理統計完成之后再繼續執行;另一個方法就是使用互斥量。

下面給出用增加一個信號量的方法來解決該問題的代碼,源文件名為semthread2.c,源代碼如下:

#include <unistd.h> #include <pthread.h> #include <semaphore.h> #include <stdlib.h> #include <stdio.h> #include <string.h>   //線程函數 void *thread_func(void *msg); sem_t sem;//信號量 sem_t sem_add;//增加的信號量   #define MSG_SIZE 512   int main() {   int res = -1;   pthread_t thread;   void *thread_result = NULL;   char msg[MSG_SIZE];   //初始化信號量,初始值為0   res = sem_init(&sem, 0, 0);   if(res == -1)   {     perror("semaphore intitialization failed/n");     exit(EXIT_FAILURE);   }   //初始化信號量,初始值為1   res = sem_init(&sem_add, 0, 1);   if(res == -1)   {     perror("semaphore intitialization failed/n");     exit(EXIT_FAILURE);   }   //創建線程,并把msg作為線程函數的參數   res = pthread_create(&thread, NULL, thread_func, msg);   if(res != 0)   {     perror("pthread_create failed/n");     exit(EXIT_FAILURE);   }   //輸入信息,以輸入end結束,由于fgets會把回車(/n)也讀入,所以判斷時就變成了“end/n”   printf("Input some text. Enter 'end'to finish.../n");      sem_wait(&sem_add);   while(strcmp("end/n", msg) != 0)   {     if(strncmp("TEST", msg, 4) == 0)     {       strcpy(msg, "copy_data/n");       sem_post(&sem);       //把sem_add的值減1,即等待子線程處理完成       sem_wait(&sem_add);     }     fgets(msg, MSG_SIZE, stdin);     //把信號量加1     sem_post(&sem);     //把sem_add的值減1,即等待子線程處理完成     sem_wait(&sem_add);   }     printf("Waiting for thread to finish.../n");   //等待子線程結束   res = pthread_join(thread, &thread_result);   if(res != 0)   {     perror("pthread_join failed/n");     exit(EXIT_FAILURE);   }   printf("Thread joined/n");   //清理信號量   sem_destroy(&sem);   sem_destroy(&sem_add);   exit(EXIT_SUCCESS); }   void* thread_func(void *msg) {   char *ptr = msg;   //把信號量減1   sem_wait(&sem);   while(strcmp("end/n", msg) != 0)   {     int i = 0;     //把小寫字母變成大寫     for(; ptr[i] != '/0'; ++i)     {       if(ptr[i] >= 'a' && ptr[i] <= 'z')       {         ptr[i] -= 'a' - 'A';       }     }     printf("You input %d characters/n", i-1);     printf("To Uppercase: %s/n", ptr);     //把信號量加1,表明子線程處理完成     sem_post(&sem_add);     //把信號量減1     sem_wait(&sem);   }   sem_post(&sem_add);   //退出線程   pthread_exit(NULL); 

其運行結果如下:

linux,多線程,信號量,信號量實現進程同步,同步信號量

分析:這里我們多使用了一個信號量sem_add,并把它的初值賦為1,在主線程在使用sem_wait來等待子線程處理完全,由于它的初值為1,所以主線程第一次調用sem_wait總是立即返回,而第二次調用則需要等待子線程處理完成之后。而在子線程中,若處理完成就會馬上使用sem_post來增加信號量的值,使主線程中的sem_wait馬上返回并執行緊接下面的代碼。從運行結果來看,運行終于正常了。注意,在線程函數中,信號量sem和sem_add使用sem_wait和sem_post函數的次序,它們的次序不能錯亂,否則在輸入end時,可能運行不正常,子線程不能正常退出,從而導致程序不能退出。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩av免费观影| 大桥未久av一区二区三区| 91超碰中文字幕久久精品| 精品一区电影国产| 在线精品播放av| 欧美色欧美亚洲高清在线视频| 国外视频精品毛片| 欧美超级免费视 在线| 日本成人黄色片| 欧美肥老太性生活视频| 97在线看福利| 日韩成人在线电影网| 日韩精品在线免费观看视频| 色综久久综合桃花网| 欧美激情欧美狂野欧美精品| 成人免费网站在线| 伊人久久久久久久久久| 国产综合久久久久久| 亚洲的天堂在线中文字幕| 久久亚洲精品视频| 亚洲男人天堂九九视频| 久久久www成人免费精品| 欧美电影免费观看高清| 久久久久99精品久久久久| 国产精品永久免费在线| 日韩免费在线看| 91老司机精品视频| 在线色欧美三级视频| 欧美电影第一页| 国产午夜精品久久久| 97成人精品区在线播放| 久久最新资源网| 久久不射电影网| 亚洲美女动态图120秒| 亚洲福利在线看| 精品国产成人av| 91sa在线看| 欧美孕妇毛茸茸xxxx| 日韩视频免费在线| 中文字幕在线看视频国产欧美在线看完整| 欧美成人中文字幕在线| 日韩小视频在线| 亚洲国产又黄又爽女人高潮的| 伊人男人综合视频网| 亚洲国产精彩中文乱码av在线播放| 草民午夜欧美限制a级福利片| 亚洲欧美制服另类日韩| 成人美女免费网站视频| 欧美日韩国产999| 45www国产精品网站| 亚洲国产精品999| 日韩中文字在线| 亚洲精品久久久久中文字幕二区| 亚洲国产精品va在线观看黑人| 91精品免费久久久久久久久| 蜜臀久久99精品久久久无需会员| 久久婷婷国产麻豆91天堂| 国产精品亚洲аv天堂网| 在线成人一区二区| 国产精品网红福利| 一区二区三区天堂av| 韩曰欧美视频免费观看| 久久99精品视频一区97| 欧美成aaa人片免费看| 国产69久久精品成人| 色无极影院亚洲| 国产精品在线看| 欧美www视频在线观看| 中文字幕日本欧美| 欧美精品video| 国产精品一区二区久久久久| 国产成人精品日本亚洲专区61| 国产精品免费小视频| 欧美中文字幕在线视频| 欧美日韩国产精品一区二区三区四区| 欧美日韩另类在线| 欧美电影在线观看完整版| 亚洲国产精品网站| 亚洲天堂开心观看| 国产欧美va欧美va香蕉在线| 8090理伦午夜在线电影| 欧美成人精品影院| 一区二区三区 在线观看视| 亚洲免费av网址| 一区二区三区四区精品| 久久香蕉国产线看观看网| 欧美高清在线视频观看不卡| 国产日韩在线视频| 国产精品国语对白| 国产v综合v亚洲欧美久久| 欧美国产日韩一区二区| 国外视频精品毛片| 97超碰蝌蚪网人人做人人爽| 欧美日韩加勒比精品一区| 国产精品91久久久| 国产精品久久久久不卡| 高清在线视频日韩欧美| 精品色蜜蜜精品视频在线观看| 影音先锋日韩有码| 91免费国产网站| 久久久国产91| 精品国模在线视频| 日韩欧美国产免费播放| 亚洲天堂精品在线| 亚洲高清免费观看高清完整版| 国产日韩中文字幕| 国产亚洲精品va在线观看| 色偷偷偷亚洲综合网另类| 亚洲福利视频网站| 亚洲福利视频在线| 国产成人精品在线播放| 亚洲天堂一区二区三区| 欧美日韩在线视频一区二区| 国产精品久久久久久久av大片| 精品国产一区二区三区久久| 国产成人精品999| 欧美极品少妇xxxxⅹ免费视频| 国产精品久久综合av爱欲tv| 国产日韩欧美影视| 国产精品一区二区三区成人| 日韩有码视频在线| 国产成人高清激情视频在线观看| 国产成人福利夜色影视| www.亚洲男人天堂| 亚洲黄色有码视频| 亚洲图片制服诱惑| 高清欧美性猛交xxxx黑人猛交| 欧美一区深夜视频| 国产精品偷伦免费视频观看的| 国产一区二区三区视频在线观看| 日产精品久久久一区二区福利| 国产婷婷成人久久av免费高清| 亚洲国产中文字幕在线观看| 亚洲午夜av久久乱码| 精品色蜜蜜精品视频在线观看| 久久久av亚洲男天堂| 色琪琪综合男人的天堂aⅴ视频| 欧美精品www| 欧美电影第一页| 在线视频一区二区| 97在线观看视频国产| 夜夜躁日日躁狠狠久久88av| 九九久久国产精品| 久久久亚洲天堂| 全亚洲最色的网站在线观看| 久久伊人色综合| 国产成人一区二区三区电影| 在线激情影院一区| 亚洲成人精品久久| 精品美女国产在线| 亚洲精品日韩激情在线电影| 菠萝蜜影院一区二区免费| 欧美成人精品一区| 欧美肥老太性生活视频| 亚洲人成伊人成综合网久久久| 国产精品日韩av| 日韩精品在线免费| 亚洲第一精品自拍| 国产成人亚洲综合| 亚洲r级在线观看| 精品日韩中文字幕| 欧美激情视频网站| 欧美电影免费观看| 国产xxx69麻豆国语对白|