【Linux】线程同步
线程同步
- 一、条件变量
- 1. 同步概念
- 2. 条件变量概念
- 3. 条件变量接口
- (1)pthread_cond_init()
- (2)pthread_cond_destroy()
- (3)pthread_cond_wait()
- (4)pthread_cond_signal()
- (5)pthread_cond_broadcast()
- (6)使用接口
- 二、生产者消费者模式
- 1. 概念
- 2. 生产者消费者模式优点
- 3. 基于 BlockingQueue 的生产者消费者模型
- 三、POSIX 信号量
- 1. 回顾信号量
- 2. POSIX 信号量接口
- (1)sem_init()
- (2)sem_destroy()
- (3)sem_wait()
- (4)sem_post()
- 3. 基于环形队列的生产消费模型
- (1)环形队列
- (2)原理
- (3)代码实现
- 四、线程池
- 五、其他常见的锁
- 六、读者写者问题
- 1. 读写锁
- 2. 读写锁口
一、条件变量
1. 同步概念
同步问题是保证数据安全的情况下,让线程访问资源具有一定的顺序性,从而有效避免饥饿问题,叫做同步。
2. 条件变量概念
所以怎么才能让线程按照一定的顺序去访问资源呢?也就是同步的解决方案是什么呢?这个解决方案在 Linux 中称为条件变量。
什么叫做条件变量呢?以前我们使用的纯加锁的时候,没有申请到加锁的线程,就直接阻塞挂起了,这个场景为纯互斥场景,也就是线程没有顺序地执行的,谁能申请到锁谁就能得到资源。而条件变量就是可以做到让线程在一个等待队列中按照顺序等待,按照它们到来的先后顺序进入队列等待,前提是这些线程都是申请锁失败的,因为是要保证资源安全的情况下。而且,在资源就绪的时候,也就是有线程释放锁后,这个条件变量还需要提供一种通知机制,唤醒一个或者全部队列中的线程,让队头的线程去访问资源。这就是条件变量。
例如一个线程访问队列时,该队列为共享资源,发现队列为空,它只能等待,直到其它线程将一个节点添加到队列中。这种情况就需要用到条件变量。
3. 条件变量接口
(1)pthread_cond_init()
初始化条件变量的接口:
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
其中第一个参数类型,也是 pthread 库给我们提供的数据类型,我们先要定义一个这样类型的条件变量,也就是要初始化的条件变量。第二个参数是属性,我们设为空即可。
条件变量的初始化和互斥锁的初始化类似,也可以定义一个全局的条件变量,用法也一样,全局或静态的条件变量可以不用初始化和释放。定义全局的条件变量如下:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
(2)pthread_cond_destroy()
释放条件变量:
int pthread_cond_destroy(pthread_cond_t *cond);
(3)pthread_cond_wait()
申请锁失败或者等待条件满足时,加入等待队列中:
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
第一个参数就是我们初始化的条件变量;第二个参数是一把锁,我们后面再介绍。
(4)pthread_cond_signal()
唤醒一个线程的接口:
int pthread_cond_signal(pthread_cond_t *cond);
(5)pthread_cond_broadcast()
唤醒所有线程:
int pthread_cond_broadcast(pthread_cond_t *cond);
(6)使用接口
下面我们将上面的接口和互斥接口一起使用起来。我们知道,当多个线程向显示器上打印时,其实就是多个线程访问同一个共享资源,此时如果不加锁,打印出来的信息就是乱的。现在我们就模拟这个场景,对显示器这个共享资源加锁,并添加条件变量实现同步。
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int cnt = 0; void* func(void* args) { pthread_detach(pthread_self()); uint64_t i = (uint64_t)args; while(1) { pthread_mutex_lock(&lock); // pthread_cond_wait 让线程加入等待队列的时候,会自动释放锁 pthread_cond_wait(&cond, &lock); cout