「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」。
条件变量
本身不是锁,通常结合锁一起使用
函数:
pthread_cond_t
pthread_cond_init //初始化条件变量
pthread_cond_destroy // 销毁条件变量
pthread_cond_wait // 线程等待(阻塞)
pthread_cond_timedwait // 线程等待(设置等待时间)
pthread_cond_signal // 唤醒(通知一个)
pthread_cond_broadcast // 唤醒(通知所有)
初始化条件变量:
静态初始化:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
动态初始化:
pthread_cond_t cond;
pthread_cond_init(&cond,NULL);
阻塞等待条件:
pthread_cond_wait(&cond,&mutex);
作用:
(1)阻塞等待条件变量cond
(2)释放已经掌握的互斥锁(相当于 pthread_mutex_unlock(&mutex))
(3)当条件满足,函数返回时,解除阻塞并重新申请获取互斥锁,重新加锁信号量(相当于:pthread_mutex_lock(&mutex));
(1)(2)为原子操作
条件变量的生产者消费者模型分析
生产者:
1、生产数据
2、加锁 : pthread_mutex_lock(&mutex);
3、将数据放入共享区
4、解锁:pthread_mutex_unlock(&mutex);
5、通知阻塞在条件变量上的线程
pthread_cond_signal(&cond) // 至少唤醒一个阻塞在条件变量上的线程
pthread_cond_broadcast(&cond) // 唤醒所有阻塞在条件变量上的线程
6、循环生产数据
消费者:
1、创建所:pthread_mutex_t mutex;
2、初始化:pthread_mutex_init(&mutex,NULL);
3、加锁:pthread_mutex_lock(&mutex);
4、等待条件满足:
pthread_cond_wait(&cond,&mutex);
(1)阻塞等待条件变量
(2)解锁 pthread_mutex_unlock(&mutex);
...
(3)加锁:pthread_mutex_lock(&mutex);
5、访问共享数据
6、解锁、释放条件变量。
代码案例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <error.h>
#include <pthread.h>
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // 初始化一个互斥量
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; // 初始化一个条件变量
struct msg
{
int num;
struct msg *next;
};
struct msg *head;
void err_thread(int ret, char *str)
{
if (ret != 0)
{
fprintf(stderr, "%s:%s\n", str, strerror(ret));
pthread_exit(NULL);
}
}
// 生产者
void *producer(void *arg)
{
struct msg *mp;
while (1)
{
// 模拟生产一个数据
mp = malloc(sizeof(struct msg));
mp->num = rand() % 100 + 1;
printf("--- producer %lu : produce a num = %d\n", pthread_self(), mp->num);
// 加锁
pthread_mutex_lock(&lock);
// 访问共享数据
mp->next = head;
head = mp;
// 解锁
pthread_mutex_unlock(&lock);
// 唤醒阻塞在条件变量 has_product 的线程
pthread_cond_broadcast(&has_product);
sleep(rand() % 5);
}
}
// 消费者
void *consumer(void *arg)
{
struct msg *mp;
while (1)
{
// 加锁
pthread_mutex_lock(&lock);
// 等待条件满足
while (head == NULL)
{
pthread_cond_wait(&has_product, &lock);
}
// 访问共享数据
mp = head;
head = mp->next;
// 解锁
pthread_mutex_unlock(&lock);
printf("--- consumer %lu : comsume a num = %d\n", pthread_self(), mp->num);
free(mp);
sleep(rand() % 5);
}
}
int main()
{
pthread_t pid, cid;
srand(time(NULL));
// 两个生产者
pthread_create(&pid, NULL, producer, NULL);
pthread_create(&pid, NULL, producer, NULL);
// 三个消费者
pthread_create(&cid, NULL, consumer, NULL);
pthread_create(&cid, NULL, consumer, NULL);
pthread_create(&cid, NULL, consumer, NULL);
pthread_join(pid, NULL);
pthread_join(cid, NULL);
return 0;
}