您的位置:首页 > 运维架构 > Linux

Linux的锁和条件变量用法 | pthread_mutex_lock | pthread_cond_signal

2013-08-16 23:36 423 查看
本篇默认读者已经清楚多线程中的锁、互斥锁、条件变量基本概念及作用,本篇只讲怎么在C++里编程调用。互斥锁很简单,条件变量(多用于生产者-消费者模型)则细节较多,本文主要说它。

主要涉及函数

#include<pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mptr); //互斥锁加锁

int pthread_mutex_unlock(pthread_mutex_t *mptr); //互斥锁解锁

int pthread_cond_signal(pthread_cond_t *cptr); //条件变量生产

int pthread_cond_wait(pthread_cond_t *cptr,pthread_mutex_t *mptr); //条件变量消费

1.互斥锁

互斥锁是要所有人抢一样东西,一个人用完之前其他人都得等着。

1)mutex_lock是阻塞加锁,即如果mptr已经被lock则等待,直到mptr被解锁。如果不希望阻塞等待,而是立即返回是否加锁成功,则使用pthread_mutext_trylock(),其返回值表示否加锁成功。

2)mutex_unlock是解锁。如果此时锁本身就是unlocked,有可能返回错误码,也可能正常返回。取决于基础库的具体实现。

2.条件变量

条件变量是要两个人相互配合,某个事情必须A做完,B才能做(比如A负责队列插入,B负责从队列取出)。正确的顺序是B先cond_wait()睡个觉,A做完,发个cond_signal(),B被唤醒继续工作。

这里一定要注意三点:

1)cond_signal() 不计数,仅唤醒一个cond_wait(),如果此时没有cond_wait()则它什么都不做!

所以要达到我们希望的效果必须B先cond_wait(),A再cond_signal()。若反过来则A的cond_signal()什么都没做,B则永远睡眠。而实际使用中保证次序肯定是开玩笑,所以需要自己维护一个计数变量count,表示当前堆积了多少A产出的产品。B在cond_wait()前先检查count是否为0,只有在count为0时才cond_wait()等待A,否则直接执行后面代码不做cond_wait()。这样A在count==0之前所做的空操作cond_signal()会以count++的形式保存下来影响B。

2)cond_wait()实际上会执行三个子操作: unlock(mutex), real_wait(), lock(mutex)

所以cond_wait()函数有两个参数,一个cond锁,一个互斥锁。cond_wait()的标准用法是:

pthread_mutex_lock(mutex);

pthread_cond_wait(); //此时先解开mutex锁,进入等待....被唤醒后再加上互斥锁

count--; //do Something ...

unlock(mutex);

猛地一看好像会死锁(mutex_lock()后就wait()了), 其实在真正等待前mutex已经被解开了,只不过唤醒后mutex又重新被锁上。

3)大杀器:即使没有cond_signal(),cond_wait() 也有可能因其它原因被唤醒

没有具体的解释,要淡定,乖乖的在判断count == 0时不用if,改用while

示例程序:

static bool alive = true;

static int count = 0;

pthread_mutex_t mutex;

pthread_cond_t cond;

void producer()

{

pthread_mutex_lock(&mutex); //加互斥锁

//...do something here, queue.insert() ...or create something...

count++;

pthread_cond_signal(&cond); //唤醒wait(),如果没有wait则什么都不做

pthread_mutex_lock(&mutex); //解互斥锁

}

void consumer()

{

pthread_mutex_lock(&mutex);//加互斥锁

while(alive && 0 == count) { //仅在count == 0 时才wait,而且是while()不是if()

pthread_cond_wait(&cond, &mutex); //内部先解互斥锁才睡眠,等唤醒后自动加回互斥锁。

}

//... do something here, queue.get() ... or use & delete something

count --;

pthread_mutex_lock(&mutex);//解互斥锁

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: