linux线程间signal,四、linux中pthread_cond_wait()与pthread_cond_signal ()解析

关于线程用法可以参考这些文章

Note: 关于内核使用线程方法可以参考之前写的另外一篇文章

这篇文章内主要介绍下pthread条件变量

条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

一 pthread_cond 相关API列表

int pthread_cond_init(pthread_cond_t *cv, pthread_cond_attr *cattr);

int pthread_cond_destroy(pthread_cond_t *cv);

int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex);

int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mutex, struct timespec *tv);

int pthread_cond_signal(pthread_cond_t *cv);

二 函数介绍

初始化条件变量:int pthread_cond_init(pthread_cond_t *cv, pthread_cond_attr *cattr);

或者使用宏 PTHREAD_COND_INITIALIZER

pthread_cond_t cond=PTHREAD_COND_INITIALIZER;

pthread_cond_t cond2;

pthread_cond_init(&cond2, NULL);

返回0表示成功,其他都表示失败。对于函数的参数:参数一创建的条件变量保存在cv所指向的内存中,pthread_cond_attr 是用来设置pthread_cond_t的属性,当传入的值是NULL的时候表示使用默认的属性,尽管POSIX标准中为条件变量定义了属性,但在LinuxThreads中没有实现,因此cond_attr值通常为NULL,且被忽略。

条件变量的销毁:int pthread_cond_destroy(pthread_cond_t *cv); 返回0表示成功,返回其他值都表示失败。

条件变量的使用: int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)以及 int pthread_cond_signal(pthread_cond_t *cv);

使用pthread_cond_wait 和 pthread_cond_signal方式如下:

// thread 1

pthread _mutex_lock(&mutex);

while或if(线程执行的条件是否成立) // Q2: 这里为什么要使用一个判断?

pthread_cond_wait(&cond, &mutex);

pthread_mutex_unlock(&mutex);

// thread 2

pthread _mutex_lock(&mutex); // Q1:如果 thread 1拿到锁 执行了wait,这里会不会死锁?

/*handling*/

pthread_cond_signal(&cond);

pthread_mutex_unlock(&mutex);

先想一个问题,就是上面的代码中,thread 1 已经持有了 mutex 后再 wait,而 thread 2 需要拿到锁才能发送 signal,这里不会阻塞造成死锁吗?

答案是不会,因为pthread_cond_wait会自动释放互斥锁。

释放互斥锁的时机是什么呢:是线程从调用pthread_cond_wait到操作系统把他放在线程等待队列之后,这样做有一个很重要的原因,就是mutex的第二个作用,保护条件。

线程是并发执行的,如果在没有把被阻塞的线程A放在等待队列之前,就释放了互斥锁,这就意味着其他线程比如线程B可以获得互斥锁去访问公有资源,这时候线程A所等待的条件改变了,但是它没有被放在等待队列上,导致A忽略了等待条件被满足的信号。倘若在线程A调用pthread_cond_wait开始,到把A放在等待队列的过程中,都持有互斥锁,其他线程无法得到互斥锁,就不能改变公有资源。这就保证了线程A被放在等待队列上之后才会有公有资源被改变的信号传递给等待队列。

引用一段解释:

The mutex passed to pthread_cond_wait protects the condition.The caller passes it locked to the function, which then atomically places the calling thread on the list of threads waiting for the condition and unlocks the mutex. This closes the window between the time that the condition is checked and the time that the thread goes to sleep waiting for the condition to change, so that the thread doesn't miss a change in the condition. When pthread_cond_wait returns, the mutex is again locked.

再看 Q2: 这里为什么要使用一个判断?

pthread_cond_signal使用只给一个线程发信号,假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。

所以pthread_cond_signal 唤醒的线程并不一定是我们要的线程或者线程要准备执行的代码前置条件,这时候我们就可以根据是否我们的期望来判断是否唤醒该线程

一个pthread_cond_signal调用最多发信一次,使用pthread_cond_broadcast则发送给所有wait cond的线程上

Demo

#include

#include

#include

#include

#include

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int count = 0;

void *decrement(void *arg) {

printf("in derement.\n");

pthread_mutex_lock(&mutex);

if (count == 0)

pthread_cond_wait(&cond, &mutex);

count--;

printf("----decrement:%d.\n", count);

printf("out decrement.\n");

pthread_mutex_unlock(&mutex);

return NULL;

}

void *increment(void *arg) {

printf("in increment.\n");

pthread_mutex_lock(&mutex);

count++;

printf("----increment:%d.\n", count);

if (count != 0)

pthread_cond_signal(&cond);

printf("out increment.\n");

pthread_mutex_unlock(&mutex);

return NULL;

}

int main(int argc, char *argv[]) {

pthread_t tid_in, tid_de;

pthread_create(&tid_de, NULL, (void*)decrement, NULL);

sleep(2);

pthread_create(&tid_in, NULL, (void*)increment, NULL);

sleep(5);

pthread_join(tid_de, NULL);

pthread_join(tid_in, NULL);

pthread_mutex_destroy(&mutex);

pthread_cond_destroy(&cond);

return 0;

}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值