c++多线程之条件变量及生产消费者模型

一、condition_variable 类介绍
当 std::condition_variable 对象的某个 wait 类函数被调用的时候,它使用std::unique_lock(通过 std::mutex)来锁住当前的线程,当前的线程会一直被阻塞(进入睡眠等待状态),直到有其他的线程在同一个 std::condition_variable 对象上调用 notify 类函数来唤醒它。

std::condition_variable 对象通常使用 std::unique_lock</std::mutex>来等待,如果需要使用另外的 lockable 类型,可以使用 std::condition_variable_any 类

1、1 wait 操作
std::condition_variable 提供了两种 wait() 函数。
(1)无条件wait()

void wait (unique_lock<mutex>& lck);

当前线程调用 wait() 后将被阻塞(此时当前线程应该获得了锁(mutex),不妨设获得锁 lck),直到另外某个线程调用 notify_* 唤醒了当前线程。
(2)有条件wait()

template <class Predicate>
void wait (unique_lock<mutex>& lck, Predicate pred);

第二种情况设置了 Predicate,只有当 pred 条件为 false 时调用 wait() 才会阻塞当前线程,并且在收到其他线程的通知后只有当 pred 为 true 时才会被解除阻塞。因此第二种情况类似以下代码:

while (!pred()) 
{
    wait(lck);
}

1、2 notify操作
(1)notify_one()

std::condition_variable::notify_one()

唤醒某个等待(wait)线程。如果当前没有等待线程,则该函数什么也不做,如果同时存在多个等待线程,则唤醒某个线程是不确定的(unspecified)。
(2)notify_all()

std::condition_variable::notify_all()

唤醒所有的等待(wait)线程。如果当前没有等待线程,则该函数什么也不做。

示例:

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

using namespace std;

std::mutex mtx;
std::condition_variable cv;
bool ready = false;//全局标志位

void printId(int i)
{
	std::unique_lock<std::mutex> lck(mtx);
	//如果标志位不为true,则等待
	while (!ready)
	{
		//线程被阻塞,直到标志位变为true
		cv.wait(lck);
	}
	cout << "thread: " << this_thread::get_id() << "  id: " << i << endl;
}
void go()
{
	std::unique_lock<std::mutex> lck(mtx);
	//改变全局变量
	ready = true;
	//唤醒所有线程
	cv.notify_all();
}

int main()
{
	std::thread threads[10];
	for (int i = 0; i < 10; ++i)
	{
		threads[i] = std::thread(printId, i);
	}
	cout << "create done." << endl;

	go();


	for (auto &t : threads)
	{
		t.join();
	}
	cout << "process done." << endl;

	system("pause");
	return 0;
}

在这里插入图片描述

二、生产者消费者模型
一般来说,生产者消费者模型可以通过 queue, mutex 和 condition_variable 来实现。下面是一个简单实现:

#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<queue>
#include<chrono>//定时
//定义了C++11标准中的一些表示线程、并发控制时原子操作的类与方法等.
#include<atomic>

using namespace std;

int main()
{
	queue<int> production;
	mutex mtx;
	condition_variable cv;
	bool ready = false;//是否有产品可以消费
	bool done = false;//生产结束

	std::thread producer(
		[&]()->void {
		for (int i = 1; i < 10; ++i)
		{
			//模拟实际生产过程
			//睡眠持续时间/毫秒。表示当前线程休眠一段时间,
			//休眠期间不与其他线程竞争CPU,根据线程需求,等待若干时间
			this_thread::sleep_for(chrono::milliseconds(10));
			cout << "producing " << i << endl;

			unique_lock<mutex> lock(mtx);
			production.push(i);

			//有产品可以消费了
			ready = true;
			cv.notify_one();
		}
		//生产结束
		done = true;
	}
	);

	std::thread consumer(
		[&]()->void {
		unique_lock<mutex> lock(mtx);
		while (!done || !production.empty())
		{
			//防止误唤醒
			while (!ready)
			{
				cv.wait(lock);
			}
			while (!production.empty())
			{
				cout << "consuming " << production.front() << endl;
				production.pop();
			}
			ready = false;
		}
	}
	);

	producer.join();
	consumer.join();

	system("pause");
	return 0;
}

在这里插入图片描述
因为上了锁,所以两个线程交替执行。
本文参考:C++11 并发编程系列(三):条件变量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中实现多线程的生产消费者模型可以使用线程库pthread。下面是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #define BUFFER_SIZE 5 int buffer[BUFFER_SIZE]; int count = 0; // 缓冲区中的数据数量 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁 pthread_cond_t empty = PTHREAD_COND_INITIALIZER; // 缓冲区为空的条件变量 pthread_cond_t full = PTHREAD_COND_INITIALIZER; // 缓冲区为满的条件变量 void* producer(void* arg) { int item; while (1) { item = rand() % 100; // 生成随机数作为生产的物品 pthread_mutex_lock(&mutex); // 加锁 while (count == BUFFER_SIZE) { // 如果缓冲区已满,等待 pthread_cond_wait(&empty, &mutex); } buffer[count++] = item; // 将物品放入缓冲区 printf("Producer produced item: %d\n", item); pthread_cond_signal(&full); // 唤醒等待的消费者 pthread_mutex_unlock(&mutex); // 解锁 } return NULL; } void* consumer(void* arg) { int item; while (1) { pthread_mutex_lock(&mutex); // 加锁 while (count == 0) { // 如果缓冲区为空,等待 pthread_cond_wait(&full, &mutex); } item = buffer[--count]; // 从缓冲区取出物品 printf("Consumer consumed item: %d\n", item); pthread_cond_signal(&empty); // 唤醒等待的生产者 pthread_mutex_unlock(&mutex); // 解锁 } return NULL; } int main() { pthread_t producer_thread, consumer_thread; pthread_create(&producer_thread, NULL, producer, NULL); pthread_create(&consumer_thread, NULL, consumer, NULL); pthread_join(producer_thread, NULL); pthread_join(consumer_thread, NULL); return 0; } ``` 这个示例代码中,定义了一个大小为5的缓冲区(使用数组实现),其中`count`变量表示缓冲区中的数据数量。生产线程通过生成随机数作为物品,并将物品放入缓冲区。消费者线程从缓冲区中取出物品并进行消费。互斥锁`mutex`用于保护临界区资源的访问,条件变量`empty`和`full`用于实现生产者和消费者之间的同步。 请注意,这只是一个简单的示例代码,没有考虑线程安全性和错误处理。在实际使用中,还需要更加细致的设计和处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值