生产者和消费者模型

基于锁和条件变量

  基于信号量的生产者消费者模型是一种经典的同步机制,用于解决多线程或多进程之间的生产者消费者问题。在 C++ 中,可以使用 std::thread 和 std::mutex 实现基于信号量的生产者消费者模型。下面是一个简单的示例代码:

#include <iostream>  
#include <thread>  
#include <mutex>  
#include <condition_variable>  
#include <queue>  
  
std::mutex mtx;  
std::condition_variable cv;  
std::queue<int> q;  
const int MAX_SIZE = 10; // 缓冲区最大容量  
  
void producer() {  
    int i = 0;  
    while (true) {  
        std::unique_lock<std::mutex> lock(mtx);  
        cv.wait(lock, []{ return q.size() < MAX_SIZE; }); // 等待缓冲区不满  
        q.push(i++);  
        std::cout << "Produced: " << i << std::endl;  
        lock.unlock();  
        cv.notify_all(); // 通知消费者可以消费  
        std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 生产间隔 1 秒  
    }  
}  
  
void consumer() {  
    while (true) {  
        std::unique_lock<std::mutex> lock(mtx);  
        cv.wait(lock, []{ return !q.empty(); }); // 等待缓冲区不空  
        int val = q.front();  
        q.pop();  
        std::cout << "Consumed: " << val << std::endl;  
        lock.unlock();  
        cv.notify_all(); // 通知生产者可以生产  
        std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 消费间隔 1 秒  
    }  
}  
  
int main() {  
    std::thread producer_thread(producer);  
    std::thread consumer_thread(consumer);  
    producer_thread.join();  
    consumer_thread.join();  
    return 0;  
}  

  在上述代码中,使用std::mutex和std::condition_variable实现同步和互斥操作,使用std::queue实现缓冲区,使用std::thread实现多线程。具体来说,生产者线程执行producer()函数,首先加锁,然后使用std::condition_variable的wait()方法等待缓冲区不满,当缓冲区不满时,生产者向缓冲区中添加数据,然后解锁并通知消费者线程可以消费。消费者线程执行consumer()函数,首先加锁,然后使用std::condition_variable的wait()方法等待缓冲区不空,当缓冲区不空时,消费者从缓冲区中取出数据,然后解锁并通知生产者线程可以生产。
  需要注意的是,在使用std::condition_variable进行同步时,需要使用std::unique_lock或者std::lock_guard类来加锁和解锁,以确保线程安全性和正确性。

基于信号量

  使用信号量实现生产者消费者模型的基本原理是:

  1. 定义两个信号量:一个用于表示缓冲区中可用的空间数量,一个用于表示缓冲区中已有的数据数量。
  2. 生产者线程在生产数据时,需要获取空间信号量的锁,如果空间信号量的值为 0,则等待消费者线程消费数据,直到有足够的空间可以生产数据。当生产者生产数据后,需要释放空间信号量的锁,并将数据数量信号量的值加 1。
  3. 消费者线程在消费数据时,需要获取数据数量信号量的锁,如果数据数量信号量的值为 0,则等待生产者线程生产数据,直到有足够的数据可以消费。当消费者消费数据后,需要释放数据数量信号量的锁,并将空间数量信号量的值加 1。

  具体实现代码如下:

#include <iostream>  
#include <thread>  
#include <mutex>  
#include <condition_variable>  
#include <queue>  
#include <semaphore.h>  
  
sem_t empty_sem; // 空闲空间信号量  
sem_t full_sem;  // 已有数据信号量  
  
std::mutex mtx;  
std::queue<int> q;  
const int MAX_SIZE = 10; // 缓冲区最大容量  
  
void producer() {  
    int i = 0;  
    while (true) {  
        sem_wait(&empty_sem); // 等待空闲空间  
        std::unique_lock<std::mutex> lock(mtx);  
        q.push(i++);  
        std::cout << "Produced: " << i << std::endl;  
        lock.unlock();  
        sem_post(&full_sem); // 释放已有数据  
        std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 生产间隔 1 秒  
    }  
}  
  
void consumer() {  
    while (true) {  
        sem_wait(&full_sem); // 等待已有数据  
        std::unique_lock<std::mutex> lock(mtx);  
        int val = q.front();  
        q.pop();  
        std::cout << "Consumed: " << val << std::endl;  
        lock.unlock();  
        sem_post(&empty_sem); // 释放空闲空间  
        std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 消费间隔 1 秒  
    }  
}  
  
int main() {  
    sem_init(&empty_sem, 0, MAX_SIZE); // 初始化空闲空间信号量  
    sem_init(&full_sem, 0, 0); // 初始化已有数据信号量  
  
    std::thread producer_thread(producer);  
    std::thread consumer_thread(consumer);  
    producer_thread.join();  
    consumer_thread.join();  
  
    sem_destroy(&empty_sem); // 销毁空闲空间信号量  
    sem_destroy(&full_sem); // 销毁已有数据信号量  
  
    return 0;  
}  

  在上述代码中,使用sem_t类型的empty_sem和full_sem表示空闲空间和已有数据的信号量,使用sem_wait()和sem_post()方法进行信号量的等待和释放操作。生产者线程和消费者线程分别使用sem_wait()和sem_post()方法等待和释放信号量,以实现缓冲区的同步和互斥操作。需要注意的是,使用信号量实现生产者消费者模型时,需要注意信号量的初始化和销毁操作,以避免资源泄漏和其他问题。同时,在使用sem_wait()方法等待信号量时,需要注意信号量的值是否为 0,以避免线程阻塞和死锁问题。
  如果觉得不错,请留下你的点赞和收藏~

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个基本的 C 语言生产者消费者模型: ``` #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #define BUFFER_SIZE 5 int buffer[BUFFER_SIZE]; int next_in = 0, next_out = 0; sem_t empty, full; pthread_mutex_t mutex; void *producer(void *args) { int i; for (i = 0; i < 10; i++) { sem_wait(&empty); pthread_mutex_lock(&mutex); buffer[next_in] = i; printf("Producer produced %d\n", i); next_in = (next_in + 1) % BUFFER_SIZE; pthread_mutex_unlock(&mutex); sem_post(&full); } pthread_exit(NULL); } void *consumer(void *args) { int i, data; for (i = 0; i < 10; i++) { sem_wait(&full); pthread_mutex_lock(&mutex); data = buffer[next_out]; printf("Consumer consumed %d\n", data); next_out = (next_out + 1) % BUFFER_SIZE; pthread_mutex_unlock(&mutex); sem_post(&empty); } pthread_exit(NULL); } int main() { pthread_t prod_thread, cons_thread; sem_init(&empty, 0, BUFFER_SIZE); sem_init(&full, 0, 0); pthread_mutex_init(&mutex, NULL); pthread_create(&prod_thread, NULL, producer, NULL); pthread_create(&cons_thread, NULL, consumer, NULL); pthread_join(prod_thread, NULL); pthread_join(cons_thread, NULL); sem_destroy(&empty); sem_destroy(&full); pthread_mutex_destroy(&mutex); return 0; } ``` 这个模型使用两个线程:一个生产者,一个消费者。它们对一个固定大小的循环缓冲区进行操作。生产者线程将数字写入缓冲区,消费者线程从缓冲区读取数字。如果缓冲区满了,生产者会等待,直到消费者从缓冲区中取出一些数据。如果缓冲区为空,消费者会等待,直到生产者放入一些数据。 这个模型需要使用互斥锁和信号量来保证线程之间的同步和互斥。互斥锁用于保护共享资源,即缓冲区和计数器。信号量用于同步线程之间的操作,即当缓冲区上有空间时通知生产者线程,当缓冲区上有数据时通知消费者线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值