条件变量
注意:条件变量和互斥变量必须一块使用
应用场景:生产者消费者问题,是线程同步的一种手段,使多个线程合理的使用资源
必要性:为了实现等待某个资源,让线程休眠。提高运行效率
初始化:
静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //初始化条件变量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //初始化互斥量
动态初始化
pthread_cond_t cond;
pthread_cond_init(&cond);//动态初始化条件变量
pthread_mutex_t mutex
pthread_mutex_init(&mutex);动态初始化互斥量
生产资源线程:
pthread_mutex_lock(&mutex); //加锁
临界区:产生临界资源(临界资源不可共享)
pthread_cond_sigal(&cond); //通知一个消费线程
或者
pthread_cond_broadcast(&cond); //广播通知多个消费线程
pthread_mutex_unlock(&mutex); //释放锁
void *taxiarv(void *arg){
printf("taxi arrived pthread\n");
pthread_detach(pthread_self());
taxi tx;
int i=1;
while(1){
tx=(taxi)malloc(sizeof(taxi_t));
tx->num=i++;
printf("taxi %d comming\n",tx->num);
pthread_mutex_lock(&lock);
tx->next=Head;
Head=tx;
pthread_cond_signal(&hastaxi);
pthread_mutex_unlock(&lock);
sleep(1);
}
pthread_exit(0);
}
消费者线程:
pthread_mutex_lock(&mutex);//加锁
while (如果没有资源){
pthread_cond_wait(&cond, &mutex); //加while是为了防止惊群效应
}
临界区:消费临界资源
pthread_mutex_unlock(&mutex); //释放锁
void *taketaxi(void *arg){
printf("take taxi pthread\n");
pthread_detach(pthread_self());
taxi tx;
while(1){
pthread_mutex_lock(&lock);
while(Head==NULL){
pthread_cond_wait(&hastaxi,&lock);
}
tx=Head;
Head=tx->next;
printf("take taxi %d\n",tx->num);
free(tx);
pthread_mutex_unlock(&lock);
}
pthread_exit(0);
}
注意:
1 pthread_cond_wait(&cond, &mutex),在没有资源等待是先unlock解锁,再休眠,等资源到了,再lock上锁
所以pthread_cond_wait 和 pthread_mutex_lock ,pthread_mutex_unlock 必须配对使用。
2 如果pthread_cond_signal或者pthread_cond_broadcast 早于 pthread_cond_wait ,则有可能会丢失信号。
3 pthead_cond_broadcast 信号会被多个线程收到,这叫线程的惊群效应。所以需要加上判断条件while循环。
注意:一个线程产生一个资源,对其它若干线程发送信号,只有其中一个线程能获取到资源,如果不加while判断,其余线程将会拿到空指针;
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
typedef struct taxi{
struct taxi *next;
int num;
}*taxi,taxi_t;
taxi Head=NULL;
pthread_cond_t hastaxi=PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
void *taxiarv(void *arg);
void *taketaxi(void *arg);
int main(){
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,taxiarv,NULL);
pthread_create(&tid2,NULL,taketaxi,NULL);
while(1){
sleep(1);
}
}
void *taxiarv(void *arg){
printf("taxi arrived pthread\n");
pthread_detach(pthread_self());
taxi tx;
int i=1;
while(1){
tx=(taxi)malloc(sizeof(taxi_t));
tx->num=i++;
printf("taxi %d comming\n",tx->num);
pthread_mutex_lock(&lock);
tx->next=Head;
Head=tx;
pthread_cond_signal(&hastaxi);
pthread_mutex_unlock(&lock);
sleep(1);
}
pthread_exit(0);
}
void *taketaxi(void *arg){
printf("take taxi pthread\n");
pthread_detach(pthread_self());
taxi tx;
while(1){
pthread_mutex_lock(&lock);
while(Head==NULL){
pthread_cond_wait(&hastaxi,&lock);
}
tx=Head;
Head=tx->next;
printf("take taxi %d\n",tx->num);
free(tx);
pthread_mutex_unlock(&lock);
}
pthread_exit(0);
}
相关函数介绍
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
如果不来信号,将会一直等待
参数:
-
cond
:指向待等待的条件变量(pthread_cond_t
类型)的指针。 -
mutex
:指向互斥锁(pthread_mutex_t
类型)的指针。在调用pthread_cond_timedwait
之前,应该先锁住这个互斥锁,以确保线程安全。
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
pthread_cond_timedwait
函数是 POSIX 线程库中用于条件变量等待的函数之一。它会使当前线程在指定的条件变量上等待,直到满足特定条件或者超时。这个函数需要传入三个参数:
-
cond
:指向待等待的条件变量(pthread_cond_t
类型)的指针。 -
mutex
:指向互斥锁(pthread_mutex_t
类型)的指针。在调用pthread_cond_timedwait
之前,应该先锁住这个互斥锁,以确保线程安全。 -
abstime
:指向struct timespec
结构的指针,用于指定等待的绝对时间。如果在指定的时间内条件变量没有被满足,线程将会被唤醒。
该函数会在以下情况之一发生时返回:
- 条件变量被满足。
- 超时时间到达。
- 函数被信号中断。
int pthread_cond_signal(pthread_cond_t *cond);
放出信号,可以访问资源(单个发送)
参数:cond
:指向待等待的条件变量(pthread_cond_t
类型)的指针。
int pthread_cond_broadcast(pthread_cond_t *cond);
放出信号,可以访问资源(广播发送)
参数:cond
:指向待等待的条件变量(pthread_cond_t
类型)的指针。