【Linux线程同步专题】三、条件变量
欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起探讨和分享Linux C/C++/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。
专栏传送门 :《Linux从小白到大神》 | 系统学习Linux开发、VIM/GCC/GDB/Make工具、Linux文件IO、进程管理、进程通信、多线程等,请关注专栏免费学习。
1. 条件变量阻塞等待
条件变量不是锁,它经常和互斥量组合使用。以生产者消费者模型为例,当前有多个消费者线程竞争一个资源,当资源为空时,消费者线程会阻塞在一个条件上,等待生产者通知,生产者写数据到临界区并通知消费者,此时消费者去竞争这个资源并读取数据。它是这样实现的,第一个线程访问资源的时候,获得互斥锁,调用pthread_cond_wait将会释放锁,并阻塞在条件cond上面,这是第二个线程到来,依然可以获得互斥锁,然后这个线程如果调用pthread_cond_wait也会会释放锁,并阻塞在条件cond上面,这样,所有线程就都阻塞在cond上面。
- 头文件及函数原型
#include <pthread.h>
/*超时等待*/
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
/*条件变量阻塞等待*/
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
-
函数描述
The pthread_cond_timedwait() and pthread_cond_wait() functions shall block on a condition variable. They shall be called with mutex locked by the calling thread or undefined behavior results.
-
函数参数
- cond:条件变量
- mutex:互斥锁
- abstime:是一个绝对时间,也就是1900年到现在的秒数(在stat函数中介绍过),如果我们要想设置abstime为10秒,应该先获取当前时间,并用这个时间加10,time(NULL)+10。
-
函数返回值
Except in the case of [ETIMEDOUT], all these error checks shall act as if they were performed immediately at the beginning of processing for the function and shall cause an error return, in effect, prior to modifying the state of the mutex specified by mutex or the condition variable specified by cond.
2. 初始化和销毁一个条件变量
- 头文件及函数原型
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
-
函数描述
- The pthread_cond_destroy() function shall destroy the given condition variable specified by cond; the object becomes, in effect, uninitialized.
- The pthread_cond_init() function shall initialize the condition variable referenced by cond with attributes referenced by attr.
-
函数参数
- cond:条件变量
- attr:属性
-
函数返回值
If successful, the pthread_cond_destroy() and pthread_cond_init() functions shall return zero; otherwise, an error number shall be returned to indicate the error.
3. 唤醒阻塞在条件上的线程
- 头文件及函数原型
#include <pthread.h>
/*唤醒阻塞在条件变量cond上的全部线程*/
int pthread_cond_broadcast(pthread_cond_t *cond);
/*唤醒至少一个阻塞在条件上的线程*/
int pthread_cond_signal(pthread_cond_t *cond);
-
函数描述
These functions shall unblock threads blocked on a condition variable. 通俗讲就是发信号告诉阻塞在条件上的线程,可以去竞争资源了。
-
函数参数
cond:条件
-
函数返回值
If successful, the pthread_cond_broadcast() and pthread_cond_signal() functions shall return zero; otherwise, an error number shall be returned to indicate the error.
4. 生产者消费者模型
生产者消费者模型的实现程序:一个生产者,两个消费者
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int gstart = 100;
typedef struct DataInfo
{
int data;
struct DataInfo* next;
}DataInfo;
DataInfo* head = NULL;
void* producer_th(void* arg)
{
while(1)
{
DataInfo* node = malloc(sizeof(DataInfo));
node->data = gstart++;
printf("thread: %s, tid: %lu, data: %d\n", __FUNCTION__,\
pthread_self(), node->data);
pthread_mutex_lock(&mutex);
node->next = head;
head = node;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
sleep(rand()%3);
}
}
void* consumer_th(void* arg)
{
while(1)
{
DataInfo* node = NULL;
pthread_mutex_lock(&mutex);
while(head == NULL)
{
/*没有数据,则阻塞*/
pthread_cond_wait(&cond, &mutex);
}
node = head;
head = head->next;
printf("th: %s, thread: %s, tid: %lu, data: %d\n",
(char*)arg, __FUNCTION__, pthread_self(), node->data);
pthread_mutex_unlock(&mutex);
sleep(rand()%3);
free(node);
}
}
int main(int argc, char* argv[])
{
pthread_t t1, t2[2];
pthread_create(&t1, NULL, producer_th, NULL);
pthread_create(&t2[0], NULL, consumer_th, "th1");
pthread_create(&t2[1], NULL, consumer_th, "th2");
pthread_join(t1, NULL);
pthread_join(t2[0], NULL);
pthread_join(t2[1], NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}