【Linux线程同步专题】三、条件变量

简介: 【Linux线程同步专题】三、条件变量

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;
}


相关文章
|
2月前
|
算法 Unix Linux
linux线程调度策略
linux线程调度策略
55 0
|
2月前
|
Java 开发者
解锁并发编程新姿势!深度揭秘AQS独占锁&ReentrantLock重入锁奥秘,Condition条件变量让你玩转线程协作,秒变并发大神!
【8月更文挑战第4天】AQS是Java并发编程的核心框架,为锁和同步器提供基础结构。ReentrantLock基于AQS实现可重入互斥锁,比`synchronized`更灵活,支持可中断锁获取及超时控制。通过维护计数器实现锁的重入性。Condition接口允许ReentrantLock创建多个条件变量,支持细粒度线程协作,超越了传统`wait`/`notify`机制,助力开发者构建高效可靠的并发应用。
78 0
|
1天前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
1月前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
1月前
|
存储 Ubuntu Linux
C语言 多线程编程(1) 初识线程和条件变量
本文档详细介绍了多线程的概念、相关命令及线程的操作方法。首先解释了线程的定义及其与进程的关系,接着对比了线程与进程的区别。随后介绍了如何在 Linux 系统中使用 `pidstat`、`top` 和 `ps` 命令查看线程信息。文档还探讨了多进程和多线程模式各自的优缺点及适用场景,并详细讲解了如何使用 POSIX 线程库创建、退出、等待和取消线程。此外,还介绍了线程分离的概念和方法,并提供了多个示例代码帮助理解。最后,深入探讨了线程间的通讯机制、互斥锁和条件变量的使用,通过具体示例展示了如何实现生产者与消费者的同步模型。
|
2月前
|
存储 设计模式 NoSQL
Linux线程详解
Linux线程详解
|
2月前
|
缓存 Linux C语言
Linux线程是如何创建的
【8月更文挑战第5天】线程不是一个完全由内核实现的机制,它是由内核态和用户态合作完成的。
|
2月前
|
Linux Shell
在Linux中,如何将二进制文件添加到 $PATH 变量中?
在Linux中,如何将二进制文件添加到 $PATH 变量中?
|
2月前
|
负载均衡 Linux 调度
在Linux中,进程和线程有何作用?
在Linux中,进程和线程有何作用?
|
2月前
|
缓存 Linux C语言
Linux中线程是如何创建的
【8月更文挑战第15天】线程并非纯内核机制,由内核态与用户态共同实现。