std::mutex和std::condition_variable理解以及实现阻塞队列和生产者与消费者模型

        C++11中的std::mutex和std::condition_variable以及std::thread跟glibc下面的pthread_mutex_t和pthread_cond_t以及pthread_create系列线程函数实现功能差不多。但是std::mutex和std::condition_variable以及std::thread可以跨平台使用,而pthread_mutex_t和pthread_cond_t以及pthread_create系列线程函数只能在Linux下使用。

        当然对于服务器端开发而言,pthread_mutex_t和pthread_cond_t及pthread_create系列线程函数也够用了,因为大部分服务器都跑在Linux下面。不过std::mutex和std::condition_variable以及std::thread用起来确实方便,下面用std::mutex和std::condition_variable实现阻塞队列,可以加深对std::mutex和std::condition_variable的运用和理解。

下面是实现代码:

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
using namespace std::chrono;

int gIndex = 0;
/*
*	阻塞队列,当pop取不到T对象时,会阻塞住,知道有新的T对象被push到队列,重新被唤醒。
*/
template
class BlockQueue {
public:	
	void push(T *data)
	{
		/*
			lock_guard在Linux服务器编程中也实现类似的轮子,利用构造析构加解锁。
			lock_guard 对象构造时,传入的 Mutex 对象(即它所管理的 Mutex 对象)进行加锁操作,当前线程锁住。
			lock_guard 对象被析构时,它所管理的 Mutex 对象进行解锁操作,当前线程会自动解锁。
			例子:

			void count_add(int index)
			{
				std::lock_guard Guard(gMutex);
				count++;
				std::cout << "thread_" << index << " count: " << count << '\n';
			}

			unique_lock 实现了lock_guard的全部功能,而且更加灵活,确定是效率可能稍差
		*/
		//加锁
		std::unique_lock lock(mutex);
		m_queue.push(data);
		/*
			notify_one:唤醒某个cond.wait线程,如果当前没有等待线程,则什么也不做。
			如果同时存在多个等待线程,则唤醒某个线程(不确定)。

			notify_all: 唤醒所有的wait线程,如果当前没有等待线程,则什么也不做。

		*/
		cond.notify_one();
	}
	T* pop()
	{
		//加锁
		std::unique_lock lock(mutex);
		while (m_queue.empty()) {
			/*
			wait:当前线程调用cond.wait(lock)后将被阻塞,直到某个线程调用notify_*唤醒当前线程;
				当线程被阻塞时,该函数会自动(调用lock对象)释放锁,使得其它被阻塞在锁竞争上的线程得以继续执行。
				一旦当前线程获得通知(notify,通常是另外某个线程调用notify_*唤醒了当前线程),wait()函数也是自动加锁(调用lock对象)。
			*/
			cond.wait(lock);
		}
		T* data = m_queue.front();
		m_queue.pop();
		return data;
	}
	int getQueueSize() { return m_queue.size(); };
private:
	std::queue m_queue;
	std::condition_variable cond;
	std::mutex mutex;
};

//生产者
void producer(BlockQueue* q, int index)
{
	cout << "producer index:" << index << endl;
	for (int i = 0; i < 10; i++)
	{	
		int* c = new int(gIndex++);
		q->push(c);
		cout << "producer_" << index << "producer:" << *c << endl;
		std::this_thread::sleep_for(milliseconds(10));
	}

}
//消费者
void consumer(BlockQueue* q, int index)
{
	cout << "consumer index:" << index << endl;
	while (1)
	{
		int* c = q->pop();
		cout << "consumer_" << index << "consumer:" << *c << endl;
		delete c;
		std::this_thread::sleep_for(milliseconds(5));
	}
}

int main() {

	BlockQueue q;

	std::thread ts[7];
	int i;
	for (i = 0; i < 5; i++)
	{
		ts[i] = std::thread(producer, &q, i + 1);
	}

	for (; i < 7; i++)
	{
		ts[i] = std::thread(consumer, &q, i + 1);
	}

	for (auto& th : ts) th.join();

	return 0;
}

你可能感兴趣的:(C++语言,c++,c++11,后端,多线程)