国产一级一区二区_segui88久久综合9999_97久久夜色精品国产_欧美色网一区二区

掃一掃
關注微信公眾號

詳解Linux操作系統中多線程的同步技術
2012-02-03   中國IT實驗室

 1 互斥鎖

  互斥鎖用來保證一段時間內只有一個線程在執行一段代碼。必要性顯而易見:假設各個線程向同一個文件順序寫入數據,最后得到的結果一定是災難性的。

  先看下面一段代碼。這是一個讀/寫程序,它們公用一個緩沖區,并且假定一個緩沖區只能保存一條信息。即緩沖區只有兩個狀態:有信息或沒有信息。

  void reader_function ( void );

  void writer_function ( void );

  char buffer;

  int buffer_has_item=0;

  pthread_mutex_t mutex;

  struct timespec delay;

  void main ( void ){

  pthread_t reader;

  /* 定義延遲時間*/

  delay.tv_sec = 2;

  delay.tv_nec = 0;

  /* 用默認屬性初始化一個互斥鎖對象*/

  pthread_mutex_init (&mutex,NULL);

  pthread_create(&reader, pthread_attr_default, (void *)&reader_function), NULL);

  writer_function( );

  }

  void writer_function (void){

  while(1){

  /* 鎖定互斥鎖*/

  pthread_mutex_lock (&mutex);

  if (buffer_has_item==0){

  buffer=make_new_item( );

  buffer_has_item=1;

  }

  /* 打開互斥鎖*/

  pthread_mutex_unlock(&mutex);

  pthread_delay_np(&delay);

  }

  }

  void reader_function(void){

  while(1){

  pthread_mutex_lock(&mutex);

  if(buffer_has_item==1){

  consume_item(buffer);

  buffer_has_item=0;

  }

  pthread_mutex_unlock(&mutex);

  pthread_delay_np(&delay);

  }

  }

  這里聲明了互斥鎖變量mutex,結構pthread_mutex_t為不公開的數據類型,其中包含一個系統分配的屬性對象。函數pthread_mutex_init用來生成一個互斥鎖。NULL參數表明使用默認屬性。如果需要聲明特定屬性的互斥鎖,須調用函數pthread_mutexattr_init。函數pthread_mutexattr_setpshared和函數pthread_mutexattr_settype用來設置互斥鎖屬性。前一個函數設置屬性pshared,它有兩個取值,PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。前者用來不同進程中的線程同步,后者用于同步本進程的不同線程。在上面的例子中,使用的是默認屬性PTHREAD_PROCESS_ PRIVATE。后者用來設置互斥鎖類型,可選的類型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE和PTHREAD _MUTEX_DEFAULT。它們分別定義了不同的上鎖、解鎖機制,一般情況下,選用最后一個默認屬性。

  pthread_mutex_lock聲明開始用互斥鎖上鎖,此后的代碼直至調用pthread_mutex_unlock為止,均被上鎖,即同一時間只能被一個線程調用執行。當一個線程執行到pthread_mutex_lock處時,如果該鎖此時被另一個線程使用,那此線程被阻塞,即程序將等待到另一個線程釋放此互斥鎖。在上面的例子中,使用了pthread_delay_np函數,讓線程睡眠一段時間,就是為了防止一個線程始終占據此函數。

  在使用互斥鎖的過程中很有可能會出現死鎖:兩個線程試圖同時占用兩個資源,并按不同的次序鎖定相應的互斥鎖,例如兩個線程都需要鎖定互斥鎖1和互斥鎖2,a線程先鎖定互斥鎖1,b線程先鎖定互斥鎖2,這時就出現了死鎖。此時可以使用函數pthread_mutex_trylock,它是函數pthread_mutex_lock的非阻塞版本,當它發現死鎖不可避免時,它會返回相應的信息,程序員可以針對死鎖做出相應的處理。另外不同的互斥鎖類型對死鎖的處理不一樣,但最主要的還是要程序員自己在程序設計注意這一點。

#p#副標題#e#

2 條件變量

  前一節中我們講述了如何使用互斥鎖來實現線程間數據的共享和通信,互斥鎖一個明顯的缺點是它只有兩種狀態:鎖定和非鎖定。而條件變量通過允許線程阻塞和等待另一個線程發送信號的方法彌補了互斥鎖的不足,它常和互斥鎖一起使用。使用時,條件變量被用來阻塞一個線程,當條件不滿足時,線程往往解開相應的互斥鎖并等待條件發生變化。一旦其它的某個線程改變了條件變量,它將通知相應的條件變量喚醒一個或多個正被此條件變量阻塞的線程。這些線程將重新鎖定互斥鎖并重新測試條件是否滿足。一般說來,條件變量被用來進行線程間的同步。

  條件變量的結構為pthread_cond_t,函數pthread_cond_init()被用來初始化一個條件變量。它的原型為:

  extern int pthread_cond_init __P ((pthread_cond_t *__cond,__const pthread_condattr_t *__cond_attr));

  其中cond是一個指向結構pthread_cond_t的指針,cond_attr是一個指向結構pthread_condattr_t的指針。結構pthread_condattr_t是條件變量的屬性結構,和互斥鎖一樣可以用它來設置條件變量是進程內可用還是進程間可用,默認值是PTHREAD_ PROCESS_PRIVATE,即此條件變量被同一進程內的各個線程使用。注意初始化條件變量只有未被使用時才能重新初始化或被釋放。釋放一個條件變量的函數為pthread_cond_ destroy(pthread_cond_t cond)。

  函數pthread_cond_wait()使線程阻塞在一個條件變量上。它的函數原型為:

  extern int pthread_cond_wait __P ((pthread_cond_t *__cond,

  pthread_mutex_t *__mutex));

  線程解開mutex指向的鎖并被條件變量cond阻塞。線程可以被函數pthread_cond_signal和函數pthread_cond_broadcast喚醒,但是要注意的是,條件變量只是起阻塞和喚醒線程的作用,具體的判斷條件還需用戶給出,例如一個變量是否為0等等,這一點從后面的例子中可以看到。線程被喚醒后,它將重新檢查判斷條件是否滿足,如果還不滿足,一般說來線程應該仍阻塞在這里,被等待被下一次喚醒。這個過程一般用while語句實現。

  另一個用來阻塞線程的函數是pthread_cond_timedwait(),它的原型為:

  extern int pthread_cond_timedwait __P ((pthread_cond_t *__cond,

  pthread_mutex_t *__mutex, __const struct timespec *__abstime));

  它比函數pthread_cond_wait()多了一個時間參數,經歷abstime段時間后,即使條件變量不滿足,阻塞也被解除。

  函數pthread_cond_signal()的原型為:

  extern int pthread_cond_signal __P ((pthread_cond_t *__cond));

  它用來釋放被阻塞在條件變量cond上的一個線程。多個線程阻塞在此條件變量上時,哪一個線程被喚醒是由線程的調度策略所決定的。要注意的是,必須用保護條件變量的互斥鎖來保護這個函數,否則條件滿足信號有可能在測試條件和調用pthread_cond_wait函數之間被發出,從而造成無限制的等待。下面是使用函數pthread_cond_wait()和函數pthread_cond_signal()的一個簡單的例子。

  pthread_mutex_t count_lock;

  pthread_cond_t count_nonzero;

  unsigned count;

  decrement_count () {

  pthread_mutex_lock (&count_lock);

  while(count==0)

  pthread_cond_wait( &count_nonzero, &count_lock);

  count=count -1;

  pthread_mutex_unlock (&count_lock);

  }

  increment_count(){

  pthread_mutex_lock(&count_lock);

  if(count==0)

  pthread_cond_signal(&count_nonzero);

  count=count+1;

  pthread_mutex_unlock(&count_lock);

  }

  count值為0時,decrement函數在pthread_cond_wait處被阻塞,并打開互斥鎖count_lock。此時,當調用到函數increment_count時,pthread_cond_signal()函數改變條件變量,告知decrement_count()停止阻塞。

  函數pthread_cond_broadcast(pthread_cond_t *cond)用來喚醒所有被阻塞在條件變量cond上的線程。這些線程被喚醒后將再次競爭相應的互斥鎖,所以必須小心使用這個函數。

#p#副標題#e#

 3 信號量

  信號量本質上是一個非負的整數計數器,它被用來控制對公共資源的訪問。當公共資源增加時,調用函數sem_post()增加信號量。只有當信號量值大于0時,才能使用公共資源,使用后,函數sem_wait()減少信號量。函數sem_trywait()和函數pthread_ mutex_trylock()起同樣的作用,它是函數sem_wait()的非阻塞版本。下面逐個介紹和信號量有關的一些函數,它們都在頭文件/usr/include/semaphore.h中定義。

  信號量的數據類型為結構sem_t,它本質上是一個長整型的數。函數sem_init()用來初始化一個信號量。它的原型為:

  extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));

  sem為指向信號量結構的一個指針;pshared不為0時此信號量在進程間共享,否則只能為當前進程的所有線程共享;value給出了信號量的初始值。

  函數sem_post( sem_t *sem )用來增加信號量的值。當有線程阻塞在這個信號量上時,調用這個函數會使其中的一個線程不再阻塞,選擇機制同樣是由線程的調度策略決定的。

  函數sem_wait( sem_t *sem )被用來阻塞當前線程直到信號量sem的值大于0,解除阻塞后將sem的值減一,表明公共資源經使用后減少。函數sem_trywait ( sem_t *sem )是函數sem_wait()的非阻塞版本,它直接將信號量sem的值減一。

  函數sem_destroy(sem_t *sem)用來釋放信號量sem。

  下面來看一個使用信號量的例子。在這個例子中,一共有4個線程,其中兩個線程負責從文件讀取數據到公共的緩沖區,另兩個線程從緩沖區讀取數據作不同的處理(加和乘運算)。

  /* File sem.c */

  #include

  #include

  #include

  #define MAXSTACK 100

  int stack[MAXSTACK][2];

  int size=0;

  sem_t sem;

  /* 從文件1.dat讀取數據,每讀一次,信號量加一*/

  void ReadData1(void){

  FILE *fp=fopen("1.dat","r");

  while(!feof(fp)){

  fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);

  sem_post(&sem);

  ++size;

  }

  fclose(fp);

  }

  /*從文件2.dat讀取數據*/

  void ReadData2(void){

  FILE *fp=fopen("2.dat","r");

  while(!feof(fp)){

  fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);

  sem_post(&sem);

  ++size;

  }

  fclose(fp);

  }

  /*阻塞等待緩沖區有數據,讀取數據后,釋放空間,繼續等待*/

  void HandleData1(void){

  while(1){

  sem_wait(&sem);

  printf("Plus:%d+%d=%d\n",stack[size][0],stack[size][1],

  stack[size][0]+stack[size][1]);

  --size;

  }

  }

  void HandleData2(void){

  while(1){

  sem_wait(&sem);

  printf("Multiply:%d*%d=%d\n",stack[size][0],stack[size][1],

  stack[size][0]*stack[size][1]);

  --size;

  }

  }

  int main(void){

  pthread_t t1,t2,t3,t4;

  sem_init(&sem,0,0);

  pthread_create(&t1,NULL,(void *)HandleData1,NULL);

  pthread_create(&t2,NULL,(void *)HandleData2,NULL);

  pthread_create(&t3,NULL,(void *)ReadData1,NULL);

  pthread_create(&t4,NULL,(void *)ReadData2,NULL);

  /* 防止程序過早退出,讓它在此無限期等待*/

  pthread_join(t1,NULL);

  }

  在Linux下,用命令gcc -lpthread sem.c -o sem生成可執行文件sem。事先編輯好數據文件1.dat和2.dat,假設它們的內容分別為1 2 3 4 5 6 7 8 9 10和 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 ,運行sem,得到如下的結果:

  Multiply:-1*-2=2

  Plus:-1+-2=-3

  Multiply:9*10=90

  Plus:-9+-10=-19

  Multiply:-7*-8=56

  Plus:-5+-6=-11

  Multiply:-3*-4=12

  Plus:9+10=19

  Plus:7+8=15

  Plus:5+6=11

  從中可以看出各個線程間的競爭關系。而數值并未按原先的順序顯示出來,這是由于size這個數值被各個線程任意修改的緣故。這也往往是多線程編程要注意的問題。

轉載鏈接:http://server.zol.com.cn/271/2715453.html

熱詞搜索:

上一篇:甲骨文推通信類Netra SPARC T4服務器
下一篇:匯總:Windows 8的那些特色功能[組圖]

分享到: 收藏
国产一级一区二区_segui88久久综合9999_97久久夜色精品国产_欧美色网一区二区
色婷婷久久久久swag精品| 亚洲欧洲日韩综合一区二区| 国产精品嫩草99a| 精品国产污污免费网站入口 | 日韩精品一二区| 亚洲高清不卡在线| 午夜精品一区在线观看| 午夜激情久久久| 蜜臀av性久久久久av蜜臀妖精| 日本免费新一区视频| 久久精品二区亚洲w码| 国产乱子轮精品视频| 国产精品小仙女| 91在线精品一区二区三区| 99久久免费视频.com| 色婷婷综合久色| 欧美日韩国产美| 精品国产一区二区三区久久久蜜月| 亚洲精品一区二区精华| 国产精品美女www爽爽爽| 亚洲人成网站影音先锋播放| 亚洲影院在线观看| 日韩av网站在线观看| 国产一区二区在线影院| 成人av片在线观看| 欧美日韩亚洲综合在线| 欧美成人精品二区三区99精品| 国产午夜精品理论片a级大结局| 成人免费在线视频观看| 天堂一区二区在线| 国产福利一区在线| 色狠狠综合天天综合综合| 欧美军同video69gay| 久久综合色之久久综合| 综合激情成人伊人| 偷拍一区二区三区四区| 国产精品综合av一区二区国产馆| 99精品一区二区| 日韩一区二区精品葵司在线| 中文字幕第一区二区| 亚洲国产精品一区二区尤物区| 另类综合日韩欧美亚洲| 97精品电影院| 欧美成人bangbros| 国产成人精品亚洲日本在线桃色 | 欧美mv日韩mv国产网站app| 国产目拍亚洲精品99久久精品| 一区二区三区av电影| 狠狠狠色丁香婷婷综合久久五月| 色偷偷88欧美精品久久久| 日韩免费看网站| 亚洲女同ⅹxx女同tv| 久久精品国产一区二区| 91亚洲永久精品| 26uuu色噜噜精品一区| 亚洲一区在线观看网站| 豆国产96在线|亚洲| 宅男在线国产精品| 亚洲激情图片qvod| 国产盗摄一区二区| 欧美一区二区大片| 亚洲综合成人网| 成人午夜在线播放| 精品国产免费一区二区三区四区 | 日本少妇一区二区| 色美美综合视频| 日本一区二区综合亚洲| 蜜桃久久久久久| 欧美午夜精品免费| 一区在线中文字幕| 成人在线综合网站| 精品国产不卡一区二区三区| 亚洲国产视频一区| 99久久精品一区| 久久九九影视网| 九九九精品视频| 欧美精品欧美精品系列| 一区二区三区中文在线| 99麻豆久久久国产精品免费优播| 精品99一区二区| 美女视频黄频大全不卡视频在线播放| 色哟哟在线观看一区二区三区| 欧美韩国日本一区| 国产一区二区精品久久91| 91精品国产品国语在线不卡| 亚洲第一在线综合网站| 在线免费观看日韩欧美| 亚洲三级免费观看| 成人妖精视频yjsp地址| 国产欧美一区二区精品婷婷| 经典三级视频一区| 欧美精品一区二区三区很污很色的| 日韩精品成人一区二区三区| 欧美三区免费完整视频在线观看| 亚洲激情在线激情| 一本大道av伊人久久综合| 最新久久zyz资源站| 高清成人免费视频| 国产精品午夜免费| 成人va在线观看| 自拍偷拍国产亚洲| www.综合网.com| 1区2区3区国产精品| 91在线无精精品入口| 亚洲欧美国产毛片在线| 欧美在线制服丝袜| 日韩高清一区在线| 日韩精品一区国产麻豆| 麻豆精品视频在线观看视频| 精品美女一区二区| 国产成人高清视频| **性色生活片久久毛片| 色又黄又爽网站www久久| 亚洲国产精品久久人人爱| 4438x成人网最大色成网站| 奇米影视在线99精品| 久久影院午夜论| 成人h精品动漫一区二区三区| 亚洲欧美怡红院| 欧美日韩亚洲高清一区二区| 日本在线不卡一区| 久久免费美女视频| 91性感美女视频| 午夜久久久久久久久| 欧美videos大乳护士334| 欧美女孩性生活视频| 狠狠狠色丁香婷婷综合激情| 亚洲国产成人午夜在线一区| 在线区一区二视频| 捆绑调教一区二区三区| 久久久久久久性| 色综合天天综合网天天看片| 五月天婷婷综合| 久久精品视频免费观看| 91在线观看一区二区| 亚洲成人在线观看视频| 亚洲精品在线网站| 色哟哟一区二区三区| 免费在线观看一区二区三区| 中文字幕欧美区| 欧美日韩小视频| 国产成人激情av| 亚洲自拍另类综合| 精品国产亚洲在线| 91福利在线观看| 极品美女销魂一区二区三区| 亚洲欧美日韩综合aⅴ视频| 91麻豆精品国产自产在线观看一区 | 懂色av一区二区三区免费观看| 亚洲欧美日韩小说| 欧美一区二区精品| 成人av在线观| 美美哒免费高清在线观看视频一区二区| 欧美国产精品中文字幕| 欧美日韩国产精品自在自线| 国产91精品露脸国语对白| 午夜电影网一区| 国产精品乱码一区二三区小蝌蚪| 欧美日韩精品是欧美日韩精品| 国产露脸91国语对白| 天堂va蜜桃一区二区三区漫画版| 国产精品三级av在线播放| 日韩一区二区精品葵司在线| 91视频你懂的| 国产麻豆视频一区二区| 日韩不卡一区二区三区| 亚洲日本在线视频观看| 久久蜜桃av一区二区天堂| 欧美日韩国产片| 91免费在线视频观看| 国产一区二区中文字幕| 奇米色777欧美一区二区| 亚洲免费在线电影| 亚洲国产精品二十页| 欧美大片国产精品| **网站欧美大片在线观看| 欧美精品一区二区三区一线天视频| 欧美网站大全在线观看| 99国产精品久久久久久久久久| 国产综合久久久久久久久久久久| 亚洲成人av在线电影| 一区二区三区在线免费视频| 欧美激情一区二区三区蜜桃视频| 欧美va亚洲va| 91精品麻豆日日躁夜夜躁| 欧美视频一区在线观看| 在线一区二区观看| 91伊人久久大香线蕉| 成人av网站大全| 成人美女视频在线看| 国产传媒日韩欧美成人| 国内精品伊人久久久久av一坑| 日本午夜精品视频在线观看| 五月综合激情网| 亚洲成人激情av| 亚洲r级在线视频| 亚洲一区二区欧美| 亚洲一级不卡视频| 亚洲一区二区三区在线| 亚洲大片精品永久免费|