3.13、条件变量
1.条件变量
- 在多线程编程中,条件变量是一种同步机制,常常和锁一起使用。条件变量通常用于线程之间的通信,用于等待和唤醒某个条件的出现。条件变量实际上是一个由系统内核提供的等待队列,线程在这个等待队列上等待条件的出现,而不是忙等待。
- 条件变量的基本操作有等待和唤醒两种。当线程在等待某个条件的时候,它会阻塞在条件变量上。当有其他线程满足了这个条件并通过条件变量唤醒了该线程时,该线程被唤醒并重新进入运行状态。
- 在使用条件变量时,需要先获得锁,然后才能对条件变量进行操作。条件变量的等待操作会将锁释放,从而允许其他线程对共享资源进行操作。而唤醒操作则会重新获得锁。
2.条件变量的常用函数
- 条件变量的类型
pthread_cond_t
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
初始化条件变量int pthread_cond_destroy(pthread_cond_t *cond);
销毁条件变量int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
等待条件变量int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
等待进程多时间int pthread_cond_signal(pthread_cond_t *cond);
唤醒等待条件变量的线程中的一个线程int pthread_cond_broadcast(pthread_cond_t *cond);
唤醒等待条件变量的所有线程
3.条件变量实现生产者消费者模型(含函数介绍)
pthread_cond_wait函数可被多个线程使用
/*
条件变量的类型 pthread_cond_t
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
- 等待,调用了该函数,线程会阻塞。
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
- 等待多长时间,调用了这个函数,线程会阻塞,直到指定的时间结束。
int pthread_cond_signal(pthread_cond_t *cond);
- 唤醒一个或者多个等待的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
- 唤醒所有的等待的线程
*/
#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
// 定义锁
pthread_mutex_t mutex;
// 定义条件变量
pthread_cond_t cond;
struct Node
{
int num;
Node * next;
Node(int _num): num(_num), next(nullptr) {
}
};
Node * head = nullptr;
void * producer(void * arg)
{
while (1)
{
// 加锁
pthread_mutex_lock(&mutex);
Node * newNode = new Node(rand() % 1000);
newNode->next = head;
head = newNode;
printf("add: %d, tid: %ld\n", newNode->num, pthread_self());
// 告诉他们别的线程可以不用阻塞了
pthread_cond_signal(&cond);
// 解锁
pthread_mutex_unlock(&mutex);
usleep(100);
}
pthread_exit(NULL);
}
void * customer(void * arg)
{
while (1)
{
// 加锁
pthread_mutex_lock(&mutex);
if (head == nullptr)
{
// 如果为空,阻塞住进程
// 阻塞的时候会将mutex解锁,收到信号之后又会加锁,并且不阻塞
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
continue;
}
Node * tmp = head;
head = head->next;
printf ("del: %d, tid: %ld\n", tmp->num, pthread_self());
delete tmp;
tmp = nullptr;
// 解锁
pthread_mutex_unlock(&mutex);
usleep(100);
}
pthread_exit(NULL);
}
int main()
{
// 初始化锁和条件变量
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
// 创建线程
pthread_t ptid[5], ctid[5];
for (int i = 0; i < 5; i ++ )
{
// pthread_create(&ptid[i], &attr, producer, NULL);
// pthread_create(&ctid[i], &attr, customer, NULL);
pthread_create(&ptid[i], NULL, producer, NULL);
pthread_create(&ctid[i], NULL, customer, NULL);
}
// 设置线程分离
for (int i = 0; i < 5; i ++ )
{
pthread_detach(ptid[i]);
pthread_detach(ctid[i]);
}
// 设置
while (1)
{
sleep(1);
}
// 释放释放锁和条件变量
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
// 退出主线程
pthread_exit(NULL);
return 0;
}