【Linux操作系统】Linux系统编程中条件变量实现生产者消费者模型

在Linux系统编程中,条件变量是一种用于线程间同步的机制,常用于实现生产者消费者模型。生产者消费者模型是一种常见的并发编程模型,用于解决多线程环境下的数据共享和同步问题。在该模型中,生产者负责生产数据,消费者负责消费数据,而条件变量则用于在生产者和消费者之间进行同步。

\

文章目录

    • 原理
    • 相关函数
      • [1. pthread_cond_init](#1. pthread_cond_init "#1_pthread_cond_init_14")
      • [2. pthread_cond_destroy](#2. pthread_cond_destroy "#2_pthread_cond_destroy_24")
      • [3. pthread_cond_wait](#3. pthread_cond_wait "#3_pthread_cond_wait_33")
      • [4. pthread_cond_signal](#4. pthread_cond_signal "#4_pthread_cond_signal_43")
      • [5. pthread_cond_broadcast](#5. pthread_cond_broadcast "#5_pthread_cond_broadcast_52")
    • 示例和代码解释

原理

条件变量是一种基于互斥锁的线程同步机制,它允许线程在满足特定条件之前等待,并在条件满足时被唤醒。在生产者消费者模型中,条件变量用于控制生产者和消费者之间的数据传递和同步。

条件变量通常与互斥锁配合使用。互斥锁用于保护共享资源,而条件变量用于在特定条件下等待和唤醒线程。当某个线程需要等待某个条件时,它会释放互斥锁并进入等待状态。当其他线程满足了条件并调用相应的函数来通知等待线程时,等待线程会被唤醒并重新获取互斥锁。

相关函数

1. pthread_cond_init

c 复制代码
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
  • 功能:初始化条件变量

  • 参数:

    • cond:指向条件变量的指针
    • attr:条件变量的属性,通常为NULL
  • 返回值:成功返回0,失败返回错误码

2. pthread_cond_destroy

c 复制代码
int pthread_cond_destroy(pthread_cond_t *cond);
  • 功能:销毁条件变量

  • 参数:

    • cond:指向条件变量的指针
  • 返回值:成功返回0,失败返回错误码

3. pthread_cond_wait

c 复制代码
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
  • 功能:等待条件变量满足

  • 参数:

    • cond:指向条件变量的指针
    • mutex:指向互斥锁的指针
  • 返回值:成功返回0,失败返回错误码

4. pthread_cond_signal

c 复制代码
int pthread_cond_signal(pthread_cond_t *cond);
  • 功能:唤醒等待条件变量的一个线程

  • 参数:

    • cond:指向条件变量的指针
  • 返回值:成功返回0,失败返回错误码

5. pthread_cond_broadcast

c 复制代码
int pthread_cond_broadcast(pthread_cond_t *cond);
  • 功能:唤醒等待条件变量的所有线程

  • 参数:

    • cond:指向条件变量的指针
  • 返回值:成功返回0,失败返回错误码

示例和代码解释

下面是一个使用条件变量实现生产者消费者模型的示例代码:

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define BUFFER_SIZE 10

int buffer[BUFFER_SIZE];
int count = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;

void *producer(void *arg) {
    int i;
    for (i = 0; i < BUFFER_SIZE; i++) {
        pthread_mutex_lock(&mutex);
        while (count == BUFFER_SIZE) {
            pthread_cond_wait(&cond, &mutex);
        }
        buffer[count++] = i;
        printf("Produced: %d\n", i);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
    pthread_exit(NULL);
}

void *consumer(void *arg) {
    int i;
    for (i = 0; i < BUFFER_SIZE; i++) {
        pthread_mutex_lock(&mutex);
        while (count == 0) {
            pthread_cond_wait(&cond, &mutex);
        }
        int item = buffer[--count];
        printf("Consumed: %d\n", item);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
    pthread_exit(NULL);
}

int main() {
    pthread_t producer_thread, consumer_thread;

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);

    pthread_create(&producer_thread, NULL, producer, NULL);
    pthread_create(&consumer_thread, NULL, consumer, NULL);

    pthread_join(producer_thread, NULL);
    pthread_join(consumer_thread, NULL);

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    return 0;
}

上述代码中,我们定义了一个大小为10的缓冲区(buffer),生产者线程负责向缓冲区中生产数据,消费者线程负责从缓冲区中消费数据。

在生产者线程中,我们首先获取互斥锁,然后检查缓冲区是否已满。如果缓冲区已满,则调用pthread_cond_wait函数等待条件变量满足,此时会自动释放互斥锁。当其他线程调用pthread_cond_signal函数唤醒等待的线程时,生产者线程会被唤醒并重新获取互斥锁。然后,我们将数据放入缓冲区,打印生产的数据,并调用pthread_cond_signal函数唤醒可能等待的消费者线程。最后,释放互斥锁。

在消费者线程中,我们也首先获取互斥锁,然后检查缓冲区是否为空。如果缓冲区为空,则调用pthread_cond_wait函数等待条件变量满足,此时会自动释放互斥锁。当其他线程调用pthread_cond_signal函数唤醒等待的线程时,消费者线程会被唤醒并重新获取互斥锁。然后,我们从缓冲区中取出数据,打印消费的数据,并调用pthread_cond_signal函数唤醒可能等待的生产者线程。最后,释放互斥锁。

在主函数中,我们创建了生产者线程和消费者线程,并等待它们的完成。最后,我们销毁条件变量和互斥锁。

通过以上代码和解释,我们可以清楚地了解条件变量在生产者消费者模型中的使用。条件变量的作用是在特定条件满足时等待和唤醒线程,从而实现线程间的同步。同时,结合互斥锁的使用,可以确保线程对共享资源的访问是安全的。

相关推荐
jjyangyou8 小时前
物联网核心安全系列——物联网安全需求
物联网·算法·安全·嵌入式·产品经理·硬件·产品设计
憧憬一下1 天前
Pinctrl子系统中Pincontroller和client驱动程序的编写
arm开发·嵌入式·c/c++·linux驱动开发
蓝天居士1 天前
ES8388 —— 带耳机放大器的低功耗立体声音频编解码器(4)
嵌入式·音频·es8388
田三番1 天前
使用 vscode 简单配置 ESP32 连接 Wi-Fi 每日定时发送 HTTP 和 HTTPS 请求
单片机·物联网·http·https·嵌入式·esp32·sntp
启明智显1 天前
AI笔筒操作说明及应用场景
人工智能·嵌入式硬件·嵌入式·ai大模型·启明智显·esp32-s3
FreakStudio2 天前
全网最适合入门的面向对象编程教程:58 Python字符串与序列化-序列化Web对象的定义与实现
python·单片机·嵌入式·面向对象·电子diy
Projectsauron5 天前
【STM32】通过 DWT 实现毫秒级延时
stm32·嵌入式·dwt
云中双月6 天前
如何使用Ida Pro和Core Dump文件定位崩溃位置(Linux下无调试符号的进程专享)
linux·嵌入式·gdb·调试·gcc·崩溃·ida pro·ulimit·core dump·cross compile
L_Z_J_I7 天前
超子物联网HAL库笔记:准备篇
笔记·物联网·嵌入式
飞凌嵌入式7 天前
FET113i-S核心板已支持RISC-V,打造国产化降本的更优解 -飞凌嵌入式
嵌入式硬件·嵌入式·risc-v·飞凌嵌入式