• POSIX条件变量


    条件变量:
      当一个线程互斥的访问某个变量时,它可能发现其他线程改变状态之前,它什么都做不了
    例如:一个线程访问队列时,发现队列为空,它只能等待,直到其他线程将一个节点添加到队列中,这种情况就需要使用条件变量。

    线程A:                                         线程B:

                                              改变n
    int n=0                                          进入临界区
    进入临界区

                                                      更改 n>0
    等待 n>0(该线程进入临界区其他的线程无法运行)                    通知等待线程
    操作n                                        退出临界区
    退出临界区

    注意:当一个线程进入临界区,等待n>0,其余的线程无法获取互斥量(同一个互斥量)进入临界区修改n,那么线程A就会一直等待。
    就会出现死锁,所以我们引入了条件变量。条件变量要跟互斥量配合使用,一是因为多个线程都可以访问条件n>0;而是因为一个线程
    对互斥量加锁,其他线程就无法获得互斥量修改n.所以条件变量一开始先解锁,那么线程就可以获得互斥量,修改n.也可以等待条件。


    条件变量使用规范
      等待条件代码:
      pthread_mutex_lock(&mutex);
      while(条件为假)
      pthread_cond_wait(cond,mutex);
      修改条件
      pthread_mutex_unlock(&mutex);

    给条件发送信号代码:
      pthread_mutex_lock(&mutex);
    设置条件为真
      pthread_cond_signal(cond);
      pthread_mutex_unlock(&mutex);

    通知条件成立
      int pthread_cond_signal(pthread_cond_t *cond);
    等待条件成立
      int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);


    while(1)
    {
    pthread_mutex_lock(&g_mutex);
    //为何使用while而不是if
    //被信号打断的话,一种pthread_cond_wait重启,就行没有发生一样,或者pthread_cond_wait可能被虚假唤醒,所以要用while再次判断条件。
    while(nready==0)
    {
    pthread_cond_wait(&g_cond,&g_mutex);
    }
    --nready;
    pthread_mutex_unlock(&g_mutex);
    }


    pthread_cond_wait(原语)内部进行的操作:
    一、对g_mutex进行解锁(其他消费者线程可以进行等待,生产者线程也可以改变条件)

    二、等待条件,直到其他线程向它发起通知
    三、返回的时候对互斥量重新加锁

    while(1)
    {
    pthread_mutex_lock(&g_mutex);
    nready++;
    if(nready>0)
    pthread_cond_signal(&g_cond);//条件满足,发起通知
    pthread_mutex_unlock(&g_mutex);
    }
      pthread_cond_signal
                向第一个等待条件的线程发起通知,如果没有任何一个线程处于等待条件的状态,这个通知将被忽略
      pthread_cond_broadcast
                向所有的等待线程发起通知

    用条件变量解决生产者、消费者问题(缓冲区无界,假定仓库无限大)

      1 #include<unistd.h>
      2 #include<sys/types.h>
      3 #include<fcntl.h>
      4 #include<sys/stat.h>
      5 #include<stdlib.h>
      6 #include<stdio.h>
      7 #include<errno.h>
      8 #include <semaphore.h>
      9 #include<pthread.h>
     10 #define ERR_EXIT(m)
     11     do
     12     {
     13         perror(m);
     14         exit(EXIT_FAILURE);
     15     }while(0)
     16 #define CONSUMERS_COUNT  2
     17 #define PRODUCERS_COUNT  4
     18 
     19 unsigned short in=0;
     20 unsigned short out=0;
     21 unsigned short produce_id=0;//当前正在消费的产品ID
     22 unsigned short consume_id=0;//当前正在消费的产品ID
     23 
     24 pthread_cond_t g_cond;
     25 pthread_mutex_t g_mutex;
     26 pthread_t  g_thread[CONSUMERS_COUNT+PRODUCERS_COUNT ];
     27 
     28 //消费者线程
     29 int nready=0;//缓冲区没有产品
     30 void* consume(void*arg)
     31 {
     32     int num=(int)arg;//线程编号
     33 
     34     while(1)
     35     {
     36         pthread_mutex_lock(&g_mutex);
     37         //当条件不成立,就一直等待。
     38         while(nready==0)    
     39         {
     40             printf("%d begin wait a condition...
    ",num);
     41             //跟互斥锁配合使用,先解锁,以便其他线程进入临界区修改条件,防止死锁。
     42             pthread_cond_wait(&g_cond,&g_mutex);//在nready==0上等待。
     43             //再加锁
     44         }
     45         //条件改变了
     46         printf("%d end wait a condition...
    ",num);
     47         printf("%d begin consume product...
    ",num);
     48         --nready;//消费产品
     49         pthread_mutex_unlock(&g_mutex);
     50         sleep(1);
     51     }    
     52     return NULL;
     53 }
     54 //生产者线程
     55 void* produce(void*arg)
     56 {    
     57     int num=(int)arg;
     58     
     59     while(1)
     60     {
     61         pthread_mutex_lock(&g_mutex);
     62         printf("%d begin produce product...
    ",num);
     63         nready++;//直接开始生产产品。
     64         printf("%d end produce product...
    ",num);
     65         //条件成立,通知等待线程
     66         pthread_cond_signal(&g_cond);
     67         printf("%d signal 
    ",num);//某个线程发起通知
     68         pthread_mutex_unlock(&g_mutex);
     69         sleep(1);
     70     }
     71     return NULL;
     72 }
     73 int main(void)
     74 {
     75     int i;
     76     //初始化互斥量和条件变量
     77     pthread_mutex_init(&g_mutex,NULL);
     78     pthread_cond_init(&g_cond,NULL);
     79     //创建消费者线程
     80     for(i=0;i<CONSUMERS_COUNT;i++)
     81     {
     82     pthread_create(&g_thread[i],NULL,consume,(void*)i);//产生了段错误.我们传递的是值,所以int num=(int)arg 而不是int num=*(int*)arg
     83     }
     84     
     85     sleep(1);//以便消费者进入等待
     86     //创建生产者线程
     87     for(i=0;i<PRODUCERS_COUNT;i++)
     88     {
     89         pthread_create(&g_thread[i+CONSUMERS_COUNT],NULL,produce,(void*)i);
     90     }
     91     //等待线程退出
     92     for(i=0;i<CONSUMERS_COUNT+PRODUCERS_COUNT;i++)
     93     {
     94         pthread_join(g_thread[i],NULL);
     95     }
     96     
     97     pthread_cond_destroy(&g_cond);
     98     pthread_mutex_destroy(&g_mutex);
     99     return 0;
    100 }
  • 相关阅读:
    display:block 的认识
    document.dcoumentElement.scrollTop
    display:block的注意
    JavaScript中的Timer是怎么工作的
    创建函数还有一种方法
    $.fn.extend()与$.extend()的使用
    jq遍历的基础语法之二
    损失函数
    Python之函数装饰器
    激活函数
  • 原文地址:https://www.cnblogs.com/wsw-seu/p/8502808.html
Copyright © 2020-2023  润新知