国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
同步

http://blog.csdn.net/zg_hover/article/details/3929833

2009


同 步

 

   在進(jìn)行多線程和多進(jìn)程編程的時候,總會遇到多個進(jìn)程或多個線程對同一塊數(shù)據(jù)的訪問。這是我們就需要使用某種同步的手段來保證數(shù)據(jù)的正確訪問。

 

1 互斥鎖和條件變量

 使用范圍:同一進(jìn)程中的不同線程間;

1.1 互斥鎖    

*基本概念
    互斥鎖是指相互排斥,是最基本的同步形式。它可以用來保護(hù)臨界區(qū),以保證任何時候都只有多個線程中的一個線程在期間運(yùn)行。

    注意:如果在多個進(jìn)程間,而且每個進(jìn)程都有獨(dú)立的互斥鎖變量的內(nèi)存空間,這樣每個進(jìn)程都可以調(diào)用pthread_mutex_lock那么這樣的互斥鎖將失去意義。例如:

下面的代碼是usp上的14-1的一段   

...

pthread_mutex_t mutex;

...

for (i = 1; i < n; i++)
      if (childpid = fork())            //創(chuàng)建進(jìn)程鏈
         break;
   snprintf(buffer, BUFSIZE,
       "i:%d  process ID:%ld  parent ID:%ld  child ID:%ld/n",
       i, (long)getpid(), (long)getppid(), (long)childpid);
 
    c = buffer;
   /********** start of critical section *****************/

   //到這里每個子進(jìn)程都擁有mutex的內(nèi)存空間和變量值,所以這里無法完成互斥

   pthread_mutex_lock(&mutex);
   while (*c != '/0') {
      fputc(*c, stderr);
      c++;
      for (i = 0; i < delay; i++)
         dummy++;
   }

   pthread_mutex_unlock(&mutex);

 /************** end of critical section **************/
   if (r_wait(NULL) == -1)
      return 1;
   ...


*鎖互斥的初始化
    .靜態(tài)初始化
        static    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    .動態(tài)初始化           
        static pthread_mutex_t lock;
        pthread_mutex_init(&lock, NULL);

*使用形式
    static    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_lock(&lock);
    ... /* 需要保護(hù)的操作 */
    pthread_mutex_unlock(&lock);

*加鎖函數(shù)
    //如果出錯則阻塞
    pthread_mutex_lock(pthread_mutex_t *lock)
    //如果出錯立即返回,errno=EBUSY
    pthread_mutex_trylock(pthread_mutex_t *lock)

1.2 條件變量
    如果沒有條件變量線程可能一直阻塞或輪訓(xùn)的方式來進(jìn)行相互的操作,也就是說線程根本就不知道是否可以進(jìn)行下面的操作而,只有進(jìn)行輪訓(xùn)去查詢看是否滿足條件。  
    條件變量和互斥鎖結(jié)合才不至于線程進(jìn)行忙等。       

*相關(guān)函數(shù)1   
    #include <pthread.h>
    int pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mpthr);
注意:
    .在使用該函數(shù)前必須要用互斥鎖鎖住線程,然后再調(diào)用該函數(shù)。
    .在沒有返回前該函數(shù)會自動釋放mpthr鎖。
    .該函數(shù)會阻塞在條件變量cptr上,
    .返回時,該函數(shù)又自動加上鎖。
    .一般的使用結(jié)構(gòu)
    pthread_mutex_lock(&l);
    while (condition is true)
        pthread_cond_wait(&cond, &l);
    pthread_mutex_unlock(&l);


*相關(guān)函數(shù)2   
    #include <pthread.h>
    int pthread_cond_broadcast(pthread_cond_t *cond);
    in pthread_cond_signal(pthread_cond_t *cptr);

 

注意:
       .第一個函數(shù)解除了所有阻塞在cond上的條件變量上的線程的阻塞。
    .第二個函數(shù)解除了至少一個阻塞在cond指向的條件變量上的線程。
    .調(diào)用這兩個函數(shù)線程可以沒有被加鎖,但如果沒有阻塞在條件變量的線程,那么它們不起任何作用。
    .如果有多個線程阻塞在條件變量cond上,那么那個先運(yùn)行決定系統(tǒng)的調(diào)度。

 

 

實(shí)例:

  1. /* 
  2.  *  生產(chǎn)者和消費(fèi)者在環(huán)形緩沖區(qū)中的實(shí)現(xiàn)和運(yùn)用 
  3.  */  
  4. #include <stdio.h>  
  5. #include <stdlib.h>  
  6. #include <string.h>  
  7. #include <unistd.h>  
  8. #include <fcntl.h>  
  9. #include <signal.h>  
  10. #include <errno.h>  
  11. #include <pthread.h>  
  12. #include <sys/types.h>   
  13. #include <sys/stat.h>  
  14. #include <time.h>  
  15. #define MAXLEN 10  
  16. struct manqueue  
  17. {  
  18.     int arrlen;   /* array total length */     
  19.     int count;    /* current queue quantity */  
  20.     int putpos;  
  21.     int getpos;  
  22. };  
  23. struct _node  
  24. {  
  25.     char name[16];  
  26.     int  ID;     
  27. };  
  28. typedef struct _node Node;    /* A Node structure. */  
  29. static  Node st[MAXLEN];   /* Buffer length */  
  30. static struct manqueue mq;  
  31. static pthread_mutex_t mutex;   
  32. static pthread_cond_t items;  
  33. static pthread_cond_t slots;  
  34. static pthread_attr_t attr;  
  35. int reader(Node *st);  
  36. int  writer(Node *pnode);  
  37. static void *workproc(void *arg);  
  38. int   
  39. main(void)  
  40. {  
  41.     /*pthread_t rtid, wrtid;*/  
  42.     int ti,tj;  
  43.     Node tst[10];  
  44.     Node rst;  
  45.     pthread_t rtid,wtid;  
  46.     mq.count = 0;  
  47.     mq.putpos = 0;  
  48.     mq.getpos = 0;  
  49.     mq.arrlen = MAXLEN;    
  50.       
  51.     pthread_attr_init(&attr);  
  52.     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);  
  53.     pthread_mutex_init(&mutex, NULL);  
  54.     pthread_cond_init(&items, NULL);      
  55.     pthread_cond_init(&slots, NULL);  
  56.       
  57.     for (tj=0; tj<3; tj++) {  
  58.         pthread_create(&rtid, NULL, (void *)reader, &rst);  
  59.     }  
  60.       
  61.     for (ti=0; ti<10; ti++) {  
  62.         strcpy(tst[ti].name, "hov");  
  63.         tst[ti].ID = ti;  
  64.         pthread_create(&wtid, NULL, (void *)writer, tst+ti);  
  65.     }  
  66.       
  67.     pause();  
  68.     exit(0);  
  69. }  
  70. /* 
  71.  * Read queue buffer data. 
  72.  */  
  73. int   
  74. reader(Node *rst)  
  75. {  
  76.     while (1) {  
  77.         pthread_mutex_lock(&mutex);  
  78.         while(mq.count <= 0) /* queue is empty */  
  79.             pthread_cond_wait(&items, &mutex);   
  80.           
  81.         memmove(rst, &st[mq.getpos], sizeof(Node));  
  82.         printf("read->[%d]=[%s-%d]/n", mq.getpos, rst->name, rst->ID);  
  83.           
  84.         mq.getpos++;  
  85.         if(mq.getpos == mq.arrlen)   /* roll to header */  
  86.             mq.getpos = 0;  
  87.         mq.count--;  
  88.         //pthread_cond_signal(&slots);  //說明有空閑的位置了。  
  89.         pthread_mutex_unlock(&mutex);     
  90.    }  
  91.     return 0;  
  92. }  
  93. /*  
  94.  * Write pnode value to the buffer queue 
  95.  */  
  96. int    
  97. writer(Node *pnode)  
  98. {  
  99.     while (1) {  
  100.         sleep(1);   //這時為了讓我們看清楚結(jié)果而加的  
  101.         pthread_mutex_lock(&mutex);  
  102.         /*      `                       //如果這里注釋掉的話,就可能使得現(xiàn)在寫的數(shù)據(jù)把 
  103.         while(mq.count >= mq.arrlen)     //已經(jīng)寫的數(shù)據(jù)覆蓋掉。所以最好是加上它。 
  104.         {                                   //如果不加的話,說明本來就有可能丟失數(shù)據(jù) 
  105.             pthread_cond_wait(&slots, &mutex); 
  106.         } 
  107.         */  
  108.         //向空閑緩沖區(qū)中放數(shù)據(jù)  
  109.         strcpy(st[mq.putpos].name, pnode->name);  
  110.         st[mq.putpos].ID = pnode->ID;  
  111.         fprintf(stderr, "write->[%d]=[%s-%d]/n",   
  112.                         mq.putpos,st[mq.putpos].name, st[mq.putpos].ID);  
  113.           
  114.         /* roll to header */  
  115.         mq.putpos++;  
  116.         if(mq.putpos == mq.arrlen)  
  117.             mq.putpos = 0;  
  118.           
  119.         mq.count++;  
  120.           
  121.         pthread_cond_signal(&items);  
  122.         pthread_mutex_unlock(&mutex);  
  123.     }     
  124.     return 0;     
  125. }  

 

 

小結(jié): 互斥鎖和條件變量一般用于同一進(jìn)程的不同線程間的同步, 用法比較簡單,應(yīng)用比較廣,比較重要的就是環(huán)形緩沖區(qū)模型,以及生產(chǎn)者消費(fèi)者模型。

 

2  posix信號燈


   信號燈是一種提供不同進(jìn)程間或一個給定進(jìn)程的不同線程間同步的原語。其中有三種信號燈比較常用:

       .posix有名信號燈

             posix有名信號燈使用posix IPC名字,可用于多個進(jìn)程和線程間的同步。

       .posix內(nèi)存信號燈

             posix內(nèi)存信號燈存放在內(nèi)存區(qū)中,可用于多個線程間的同步;如果多個進(jìn)程間有共享內(nèi)存,而信號燈變量在共享

       內(nèi)存區(qū)內(nèi),那么posix內(nèi)存信號燈也可以用于多個進(jìn)程間的同步。

       .system v 信號燈:在內(nèi)核中維護(hù),可用于進(jìn)程或線程的同步。

 

*二值信號燈和計數(shù)信號燈

    信號燈可以分為二值信號燈和計數(shù)信號燈。二值信號燈只有兩個值0或1,而計數(shù)信號燈的值可以大于1。

 

*對信號的操作

    .創(chuàng)建信號一個信號燈。通常還需要調(diào)用者指定初始值,對于二值信號燈來說,它通常是1。對于計數(shù)信號燈要具體情況具體設(shè)定。

    .等待一個信號燈(P操作)。該操作測試信號燈的值,如果其值小于或等于0,那就阻塞,一旦其值大于0就將它減1。而且該操作必須是一個原子操作。

    .掛出一個信號燈(V操作)。該操作將信號燈的值加1,如果有一些進(jìn)程等待該信號燈的值變?yōu)榇笥?,其中一個進(jìn)程現(xiàn)在就可能被喚醒。該操作也必須是一個原子操作,所做的事情有:信號燈+1;解鎖;發(fā)信號。

 

*信號燈的使用模型

    .互斥鎖模式

          sem = 1;

          sem_wait(&sem);

          臨界區(qū)

          sem_post(&sem);

 

    .生產(chǎn)者,消費(fèi)者模型

 

          生產(chǎn)者                                                                  消費(fèi)者

          get = 0;

          put = 1;

 

          for ( ; ; ) {                                                      for ( ; ; ) {

             sem_wait(&put);                                             sem_wait(&get);

             把數(shù)據(jù)放入緩沖區(qū)中                                             處理緩沖區(qū)中的數(shù)據(jù)

             sem_post(&get);                                             sem_post(&put);

          }                                                                    }

 

    .注意 :

        下面這種模型是錯誤的:

        sem_t mysem;

        sem_init(&mysem, 1, 0);   //the 2nd arg of 1 : shared between processes

        if (fork() == 0) {              //child

           ...

           sem_post(&mysem);

        }                                  

        sem_wait(&mysem);       //parent

 

        想想為什么?

          

 

*信號燈和互斥鎖的差異:

    .互斥鎖必須是由給他上鎖的線程解鎖,信號燈的掛出不必由執(zhí)行過它的等待操作的同一線程執(zhí)行。

    .在使用互斥鎖時,如果線程發(fā)送了一個信號,但是沒有線程在等待這個信號的到來,那么這個信號就會丟失。但信號量將會記下這次的信號量。不會丟失。

    .

 

*有名信號量和基于內(nèi)存的信號量的函數(shù)調(diào)用

 

                有名信號燈                               基于內(nèi)存的信號燈

              sem_open()                                sem_init()

                      /                                              /

                                                  

                                    sem_wait()

                                    sem_trywait()

                                    sem_post()

                                    sem_getvalue()

                          /                                      /

           sem_close()                               sem_destory()

           sem_unlink()

 

 

2.1 有名信號燈

 

 

     

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux之線程同步
Linux下的多線程編程
Linux下的C編程入門之“線程”控制與“線程”通信編程
Posix線程編程指南
pthread的各種同步機(jī)制
Linux C 實(shí)現(xiàn)多線程同步的四種方式(超級詳細(xì))
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服