使用c++实现生产者消费者

生产者/消费者(producer/consumer)问题,也叫作有界缓冲区(bounded buffer)问题。
假设有一个或多个生产者线程和一个或多个消费者线程。生产者把生成的数据项放入缓冲区;消费者从缓冲区取走数据项,以某种方式消费。
很多实际的系统中都会有这种场景。例如,在多线程的网络服务器中,一个生产者将HTTP 请求放入工作队列(即有界缓冲区),消费线程从队列中取走请求并处理。因为有界缓冲区是共享资源,所以我们必须通过同步机制来访问它,以免产生竞态条件。

实现环形缓冲区

首先需要一个共享缓冲区,让生产者放入数据,消费者取出数据。简单起见,我们使用一个数组来做缓冲区,put函数将值放入缓冲区,get函数从缓冲区取值。使用 fill变量记录放入缓冲区的位置,使用use变量记录get函数从缓冲区取值的位置,使用count变量记录缓冲区的使用情况。使用fill = (fill + 1) % MAX取余函数让缓冲区成环,节约空间使用。

int buffer[MAX]; 
int fill = 0; 
int use = 0; 
int count = 0;  //记录缓冲区的使用情况

void put(int value) { 
	buffer[fill] = value; 
	fill = (fill + 1) % MAX; // 当前位置是最后时,下次指向第一个位置
	count++; 
} 

int get() { 
	int tmp = buffer[use]; 
	use = (use + 1) % MAX; 
	count--; 
	return tmp; 
}

初始化锁和条件变量

初始化线程锁,条件变量emptyfull.
当缓冲区满时,使用full唤醒消费者线程
当缓冲区空时,使用empty唤醒生产者线程

std::mutex mtx;
std::condition_variable empty;
std::condition_variable full; 

实现生产者线程函数

首先获取可操作缓冲区的锁,

  1. 当缓冲区满时,生产者线程进行等待,并释放缓冲区锁
  2. 当缓冲区不满的时候,生产者线程使用put函数向缓冲区存储一个数据,并通知消费者线程,现在缓冲区已经有数据了,可以进行消费了
void producer(std::string arg) { 
	int i=0; 
	while(1) { 
        {
            std::unique_lock<std::mutex> lock(mtx);
            while(count == MAX)
                empty.wait(lock);
            put(i); // p4 
            std::cout<<arg<<" "<<i++<<std::endl; 
            full.notify_all(); // p5 
        }
	} 
} 

实现消费者线程函数

首先获取可操作缓冲区的锁,

  1. 当缓冲区空时,消费者线程进行等待,并释放缓冲区锁
  2. 当缓冲区有数据时,生产者线程使用get函数从缓冲区取出一个数据,并通知生产者线程,现在缓冲区不是满的了,可以进行生产了
void consumer(std::string arg) { 
	while(1) {
        {
            std::unique_lock<std::mutex> lock(mtx);
            while (count == 0)
                full.wait(lock);
            int tmp = get(); 
            std::cout<<arg<<" "<<tmp<<std::endl; //帮助打印是哪个消费者信息
            empty.notify_all();
        }
		//sleep(1);
	} 
}

下面是使用示例

#include <iostream>
#include <thread>
#include <mutex> 
#include <condition_variable>
#include <string>

#define MAX 10
int buffer[MAX]; 
int fill = 0; 
int use = 0; 
int count = 0; 

void put(int value) { 
	buffer[fill] = value; 
	fill = (fill + 1) % MAX; 
	count++; 
} 

int get() { 
	int tmp = buffer[use]; 
	use = (use + 1) % MAX; 
	count--; 
	return tmp; 
}
std::mutex mtx;
std::condition_variable empty;
std::condition_variable full; 

void producer(std::string arg) { 
	int i=0; 
	while(1) { 
        {
            std::unique_lock<std::mutex> lock(mtx);
            while(count == MAX)
                empty.wait(lock);
            put(i); // p4 
            std::cout<<arg<<" "<<i++<<std::endl; 
            full.notify_all(); // p5 
        }
	} 
} 

void consumer(std::string arg) { 
	while(1) {
        {
            std::unique_lock<std::mutex> lock(mtx);
            while (count == 0)
                full.wait(lock);
            int tmp = get(); 
            std::cout<<arg<<" "<<tmp<<std::endl; //帮助打印是哪个消费者信息
            empty.notify_all();
        }
		//sleep(1);
	} 
}

int main(int argc,char *argv[])
{
	
    std::thread p1(producer, "producer1");
    std::thread c1(consumer, "consumer1");
    std::thread c2(consumer, "consumer2"); //帮助打印显示信息
    p1.join();
    c1.join();
    c2.join();
	return 0;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
生产者消费者问题是一个经典的多线程同步问题,可以使用C++中的互斥锁和条件变量来实现。 以下是一个简单的生产者消费者问题的C++代码示例: ```cpp #include <iostream> #include <queue> #include <thread> #include <mutex> #include <condition_variable> using namespace std; queue<int> q; // 生产者消费者队列 mutex m; // 互斥锁 condition_variable cv; // 条件变量 const int MAX_SIZE = 10; // 队列最大容量 int product_id = 0; // 生产者生产的产品编号 // 生产者线程函数 void producer() { while (true) { unique_lock<mutex> lock(m); // 如果队列已满,则等待 cv.wait(lock, []() { return q.size() < MAX_SIZE; }); // 生产产品 q.push(++product_id); cout << "Producer produces product " << product_id << endl; // 通知消费者队列中有产品可用 cv.notify_all(); lock.unlock(); // 生产完一个产品后休眠 this_thread::sleep_for(chrono::milliseconds(500)); } } // 消费者线程函数 void consumer() { while (true) { unique_lock<mutex> lock(m); // 如果队列为空,则等待 cv.wait(lock, []() { return !q.empty(); }); // 消费产品 int product = q.front(); q.pop(); cout << "Consumer consumes product " << product << endl; // 通知生产者队列中有空位 cv.notify_all(); lock.unlock(); // 消费完一个产品后休眠 this_thread::sleep_for(chrono::milliseconds(1000)); } } int main() { thread producer_thread(producer); thread consumer_thread(consumer); producer_thread.join(); consumer_thread.join(); return 0; } ``` 在上面的代码中,我们定义了一个生产者消费者队列 `q`,一个互斥锁 `m` 和一个条件变量 `cv`。生产者线程函数 `producer` 不断地生产产品,并将其加入队列中,如果队列已满,则等待条件变量 `cv`。消费者线程函数 `consumer` 不断地消费产品,并将其从队列中移除,如果队列为空,则等待条件变量 `cv`。 在生产者线程函数中,我们使用了 `unique_lock` 对互斥锁进行加锁,然后调用 `cv.wait` 等待条件变量。在等待期间,该线程会释放互斥锁,等待其他线程调用 `notify_all` 函数通知该线程条件变量的状态发生了变化。当条件变量的状态发生变化时,线程会重新获取互斥锁并继续执行。 在消费者线程函数中,我们也使用了 `unique_lock` 对互斥锁进行加锁,并调用 `cv.wait` 等待条件变量。当队列不为空时,线程从队列中取出一个产品并进行消费,并使用 `cv.notify_all` 函数通知生产者线程队列中有空位。 在主函数中,我们创建了两个线程分别执行生产者线程函数和消费者线程函数,并等待两个线程执行完毕后退出程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值