首页 > 编程知识 正文

条件变量可以单独使用吗,条件变量原理

时间:2023-05-03 23:08:31 阅读:233890 作者:4580

条件变量相关函数、虚假唤醒

初始化一个条件变量

#include <pthread.h>int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

常量初始化

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

摧毁一个条件变量

#include <pthread.h>int pthread_cond_destroy(pthread_cond_t *cond);

条件变量阻塞等待

#include <pthread.h>int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); 先释放锁 mutex阻塞在 cond 条件变量上

超时等待

#include <pthread.h>int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); struct timespec {time_t tv_sec; /*second*/ 秒long tv_nsec; /*nanoseconds*/ 纳秒}abstime --- 绝对时间,tv_sec填写的时候 time(NULL)+600 --- 设置超时600s

唤醒至少一个阻塞在条件变量cond上的线程

#include <pthread.h>int pthread_cond_signal(pthread_cond_t *cond);

唤醒阻塞在条件变量cond上的全部线程

#include <pthread.h>int pthread_cond_broadcast(pthread_cond_t *cond);

条件变量的作用:避免无必要的竞争

线程虚假唤醒(spurious wakeup)

即使没有线程通知条件变量,线程也可能从其等待状态唤醒。

wait方法分为三个操作:
- 释放锁并阻塞
- 等待条件cond发生
- 获取通知后,竞争获取锁
-
wait只有获取到锁以后才会返回

当线程A获取通知后,会竞争获取锁,若锁被线程C获取并改变了条件变量的条件,那么当A重新拿到锁后会继续执行后面的操作,然而此时条件不允许执行后面的操作。

所以,在线程被唤醒后必须重新判断条件是否满足,如果不满足需重新等待;而且,虚假唤醒会重复发生。因此,必须使用while循环。

条件变量只有一种正确的使用方式:

对于wait端:
- 必须与mutex一起使用,该布尔表达式的读写需受此mutex保护。
- 在mutex已上锁的时候才能调用wait()
- 把判断布尔条件和wait()放到while循环中

int dequeue(){MutexLockGuard lock(mutex);while(queue.empty())//必须用循环;必须判断之后再wait(){cond.wait();//这一步会原子的unlock mutex并进入等待,不会与enqueue死锁//wait()执行完毕时会自动重新加锁}assert(!queue.empty());int top = queue.front();queue.pop_front();return top;}

对于signal/broadcast端:
- 不一定在mutex已上锁的情况下调用signal(理论上)
- 在signal之前一般要修改布尔表达式
- 修改布尔表达式通常要用mutex保护(至少用作full memory barrier)
- 注意区分signal与broadcast:broadcast通常用于表明状态变化,signal通常用于表示资源可用。

void enqueue(int x){MutexLockGuard lock(mutex);queue.push_back(x);cond.notify();//可以移出临界区之外}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。