Linux 线程 条件变量

  下面是一个多线程,生产者消费者问题,一个队列放暂存的数据:

 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...\n";
26         pthread_mutex_lock(&lock);
27         cout << "Produce in!\n";
28         int source = rand() % N;
29         cout << "Produce " << source << endl;
30         que.push(source);
31         pthread_mutex_unlock(&lock);
32         cout << "Produce out\n";
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...\n";
45         pthread_mutex_lock(&lock);
46         cout << "Consum in!\n";
47         while(que.empty())
48         {
49             pthread_cond_wait(&ready, &lock);
50             cout << "Consum from sleep\n";
51         }
52         cout << "Consum " << que.front() << endl;
53         que.pop();
54         pthread_mutex_unlock(&lock);
55         cout << "Consum out\n\n";
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);    //解锁

Linux 线程 条件变量,布布扣,bubuko.com

时间: 2024-12-24 14:07:35

Linux 线程 条件变量的相关文章

Linux线程条件变量成为取消点的陷阱

Linux线程条件变量成为取消点的陷阱 使用 pthread_cancel() 时,线程往往不会直接退出,而需要运行到取消点. pthread_cond_wait() 作为线程常见的一种阻塞,它也是一个取消点.所以,处于条件变量阻塞的线程在接收到取消信号就会直接退出. 然而,由于条件变量需要搭配互斥量使用,进入 pthread_cond_wait() 意味着互斥量上锁,此时退出线程如果不进行解锁,而且同时其他线程正在等待此条件变量,那么就会陷入死锁.因此建议使用cleanup函数在线程退出时对互

Linux Posix线程条件变量

生产者消费者模型 1.多个线程操作全局变量n,需要做成临界区(要加锁--线程锁或者信号量) 2.调用函数pthread_cond_wait(&g_cond,&g_mutex)让这个线程锁在某一个条件上等待 --pthread_cond_wait()函数的本质是①:拿到锁的线程,把锁暂时丢掉(解锁)②:线程休眠,进行等待③:线程等待通知,醒来继续执行(重新获得锁) --这个pthread_cond_wait()函数是一个原子性操作 --注意:丢掉的锁可以被生产线程获得,也可以被消费线程获得,

(转载)Linux 多线程条件变量同步

条件变量是线程同步的另一种方式,实际上,条件变量是信号量的底层实现,这也就意味着,使用条件变量可以拥有更大的自由度,同时也就需要更加小心的进行同步操作.条件变量使用的条件本身是需要使用互斥量进行保护的,线程在改变条件状态之前必须首先锁住互斥量,其他线程在获得互斥量之前不会察觉到这种改变,因为互斥量必须在锁定之后才能计算条件. 模型 #include<pthread.h> pthread_cond_t cond //准备条件变量 pthread_cond_t cond = PTHREAD_CON

Linux c 条件变量cond的使用记录

条件变量是实现线程间同步的一种方法,条件变量用来自动阻塞一个线程,直到收到收到一个cond信号或其它特殊情况发送,条件变量使用的时候必须与互斥量同时使用,这是为了保证条件量在线程间操作的"原子性". 1.创建一个条件变量cond: int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr); 在初始化一个条件变量时如果attr为 NULL,测使用默认值初始化一个条件变量cond,相当于下面的

python 线程条件变量锁

# _*_coding:utf-8_*_ # author:leo # date: # email:[email protected] import queue, threading class Worker(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.lock = threading.Lock() self.con1 = threading.Condition(self.lock) se

笔记3 linux 多线程 条件变量+互斥锁

//cond lock #include<stdio.h> #include<unistd.h> #include<pthread.h> struct test { char a[10]; char b[10]; char c[10]; }yb = {"111","222","33333"}; static int j=0; pthread_mutex_t mutex_1 = PTHREAD_MUTEX_INI

线程同步之条件变量使用手记

由来: 最近一直在想怎么高效率的在IO线程接收到数据时通知逻辑线程(基于线程池)工作的问题,像网络编程的服务器模型的一些模型都需要用到这个实现,下面我这里简单的罗列一个多线程的网络服务器模型 半同步/半异步(half-sync/half-async): 许多餐厅使用 半同步/半异步 模式的变体.例如,餐厅常常雇佣一个领班负责迎接顾客,并在餐厅繁忙时留意给顾客安排桌位,为等待就餐的顾客按序排队是必要的.领班由所有顾客"共享",不能被任何特定顾客占用太多时间.当顾客在一张桌子入坐后,有一个

Linux 线程管理

解析1 LINUX环境下多线程编程肯定会遇到需要条件变量的情况,此时必然要使用pthread_cond_wait()函数.但这个函数的执行过程比较难于理解. pthread_cond_wait()的工作流程如下(以MAN中的EXAMPLE为例):       Consider two shared variables x and y, protected by the mutex mut, and a condition vari-        able cond that is to be

Linux - 线程通信

线程互斥机制 Mutex变量就像一把"锁",是线程同步和保护共享数据的主要方式 Mutex可以用来阻止竞争 Pthreads中Mutex的基本概念 在任何时候,只有一个线程能够获得Mutex 尽管几个线程想获取一个Mutex,但是只有一个线程能够成功 其他线程需要等待,直到获取Mutex的线程放弃Mutex 线程必须轮流访问需要保护的数据 线程经常利用mutex来加锁需要更新的全局变量,这也是几个线程需要同时更新全局变量时使用的安全方法 这样能保证在多线程环境下的全局变量的更新就如在单