zoukankan      html  css  js  c++  java
  • Linux 线程 条件变量

    一:条件变量
      直接上最基本的两个函数,先抓主要矛盾:
    //等待条件
    int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restric mutex);
    
    1:把调用线程放到所等待条件的线程列表上
    2:对传进来已经加过锁的互斥量解锁
    3:线程进入休眠状态等待被唤醒
    注:1、2步为原子操作
    
    
    //通知条件
    int pthread_cond_signal(pthread_cond_t *cond);
    
    1:通知指定条件已经满足
    2:等待线程重新锁定互斥锁
    3:等待线程需要重新测试条件是否满足



     
    二:生产者消费者 
      下面是一个多线程,生产者消费者问题,一个队列放暂存的数据:
     1 #include <iostream>
     2 #include <queue>
     3 #include <stdlib.h>
     4 #include <unistd.h>
     5 #include <pthread.h>
     6 
     7 using std::cout;
     8 using std::endl;
     9 using std::queue;
    10 
    11 #define N 100
    12 #define ST 10
    13 
    14 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    15 pthread_cond_t ready = PTHREAD_COND_INITIALIZER;
    16 
    17 queue<int> que;
    18 
    19 void* threadProducer(void* arg)
    20 {
    21     while(true)
    22     {
    23         sleep(rand() % ST);
    24         
    25         cout << "Produce try in...
    ";
    26         pthread_mutex_lock(&lock);
    27         cout << "Produce in!
    ";
    28         int source = rand() % N;
    29         cout << "Produce " << source << endl;
    30         que.push(source);
    31         pthread_mutex_unlock(&lock);
    32         cout << "Produce out
    ";
    33         
    34         pthread_cond_signal(&ready);
    35     }
    36 }
    37 
    38 void* threadConsumer(void* arg)
    39 {
    40     while(true)
    41     {
    42         sleep(rand() % ST);
    43         
    44         cout << "Consum try in...
    ";
    45         pthread_mutex_lock(&lock);
    46         cout << "Consum in!
    ";
    47         while(que.empty())
    48         {
    49             pthread_cond_wait(&ready, &lock);
    50             cout << "Consum from sleep
    ";
    51         }
    52         cout << "Consum " << que.front() << endl;
    53         que.pop();
    54         pthread_mutex_unlock(&lock);
    55         cout << "Consum out
    
    ";
    56     }
    57 }
    58 
    59 int main(void)
    60 {
    61     pthread_t tProducer, tConsumer;    
    62     pthread_create(&tProducer, NULL, threadProducer, NULL);
    63     pthread_create(&tConsumer, NULL, threadConsumer, NULL);
    64     
    65     pthread_join(tProducer, NULL);
    66     pthread_join(tConsumer, NULL);
    67 
    68     exit(0);
    69 }
    生消

    看到倒数的三四行,消费者进去了,发现没有数据了,则睡眠了,然后生产者进去生产了。



     
    三:打印的例子
      下面是一个多线程的小例子,线程1打印非3的倍数,线程2打印3的倍数:
    #include <iostream>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    
    using std::cout;
    using std::endl;
    
    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t ready = PTHREAD_COND_INITIALIZER;
    
    int data = 0;
    
    void* threadProducer(void* arg)
    {
        int i;
        for(i = 1; i < 22; i++)
        {    
            sleep(1);
        
            if(i % 3 != 0)
            {
                cout << "thread1:" << i << endl;
            }
            else
            {
                pthread_mutex_lock(&lock);
                data = i;
                pthread_mutex_unlock(&lock);
                
                pthread_cond_signal(&ready);
            }    
        }
    }
    
    void* threadConsumer(void* arg)
    {
        while(true)
        {
            pthread_mutex_lock(&lock);
            while(data == 0)    //no data
                pthread_cond_wait(&ready, &lock);
            cout <<"thread2:" << data << endl;
            if(data == 21)
                break;
            else
                data = 0;    //empty data
            pthread_mutex_unlock(&lock);
        }
    }
    
    int main(void)
    {
        pthread_t tProducer, tConsumer;    
        pthread_create(&tProducer, NULL, threadProducer, NULL);
        pthread_create(&tConsumer, NULL, threadConsumer, NULL);
        
        pthread_join(tProducer, NULL);
        pthread_join(tConsumer, NULL);
    
        exit(0);
    }
    3打印

      程序大致这样:线程1中的循环,如果i不是3的倍数就自己打印了,如果是的话,把这个数放到一个地方(由于这个地方可以被线程2发现,所以要加锁访问),然后唤醒等待数据的线程2(如果线程2还没有在等待,那么这个唤醒则丢失,这是个bug,见下),线程2被唤醒后,消费了这个3的倍数,清空数据区。

      上面提到,如果唤醒线程2的消息没有被收到,则bug。看下面的代码,也就多了38一行,让线程2睡了一会,就在它睡觉的那么一会,线程1把3的倍数往那里一扔就走了,自己再继续下两个不是3倍数的数字,这就直接输出了下面两个数字,又到了3倍数,又扔过去覆盖了之前数字:
     1 #include <iostream>
     2 #include <stdlib.h>
     3 #include <unistd.h>
     4 #include <pthread.h>
     5 
     6 using std::cout;
     7 using std::endl;
     8 
     9 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    10 pthread_cond_t ready = PTHREAD_COND_INITIALIZER;
    11 
    12 int data = 0;
    13 
    14 void* threadProducer(void* arg)
    15 {
    16     int i;
    17     for(i = 1; i < 22; i++)
    18     {    
    19         sleep(1);
    20     
    21         if(i % 3 != 0)
    22         {
    23             cout << "thread1:" << i << endl;
    24         }
    25         else
    26         {
    27             pthread_mutex_lock(&lock);
    28             data = i;
    29             pthread_mutex_unlock(&lock);
    30             
    31             pthread_cond_signal(&ready);
    32         }    
    33     }
    34 }
    35 
    36 void* threadConsumer(void* arg)
    37 {
    38     sleep(20);
    39     while(true)
    40     {
    41         pthread_mutex_lock(&lock);
    42         while(data == 0)    //no data
    43             pthread_cond_wait(&ready, &lock);
    44         cout <<"thread2:" << data << endl;
    45         if(data == 21)
    46             break;
    47         else
    48             data = 0;    //empty data
    49         pthread_mutex_unlock(&lock);
    50     }
    51 }
    52 
    53 int main(void)
    54 {
    55     pthread_t tProducer, tConsumer;    
    56     pthread_create(&tProducer, NULL, threadProducer, NULL);
    57     pthread_create(&tConsumer, NULL, threadConsumer, NULL);
    58     
    59     pthread_join(tProducer, NULL);
    60     pthread_join(tConsumer, NULL);
    61 
    62     exit(0);
    63 }
    bug




     
    四:总结  
      从上面可以总结出下面的条件变量的生产者消费者代码模型:
    //下面是生产者
    
    pthread_mutex_lock(&lock);    //加锁访问临界区
    /*在这里生产数据*/
    pthread_mutex_unlock(&lock);    //解锁
        
    pthread_cond_signal(&ready);    //通知消费者
    
    
    //下面是消费者
    
    pthread_mutex_lock(&lock);    //加锁访问临界区
    while(没有待消费数据)
            pthread_cond_wait(&ready, &lock);    //睡在这里,等待被唤醒
    /*被叫醒了,在这里消费数据*/
    pthread_mutex_unlock(&lock);    //解锁
  • 相关阅读:
    Hive分组提取TopN操作
    互联网产品评论语料的观点挖掘
    Hive实现用户访问路径还原
    java基础知识——类的继承
    SVM旅程
    基于概率的相似度定义方法
    基于概率的项目相似度之并行方法
    List接口的俩个实现的区别
    奇异值分解(SVD)
    在64位机器上使用32位的dll
  • 原文地址:https://www.cnblogs.com/jiayith/p/3876624.html
Copyright © 2011-2022 走看看