2_6_7 单例、call_once、condition_variable、wait、notify_one、notify_all、生产者消费者

6_7_单例_call_once.cpp

#include "hjcommon.hpp"
#include <mutex>

using namespace std;
HJ_NS_USING

class Single // 单例类
{
private:
	Single() {}
	class GC // 内部嵌套类,析沟中释放单例对象
	{
	public:
		~GC()
		{
			cout << "delete s_instance." << endl;
			delete s_instance;
			s_instance = nullptr;
		}
	};
	static void create()
	{
		cout << "create." << endl;
		s_instance = new Single();
		static GC gc; // 析沟中释放单例对象
	}

public:
	static Single *s_instance;

	// 单例,方式一(普通方式),建议
//	static Single *getInstance()
//	{
//		if (s_instance==nullptr) // 双重锁定,让已经初始化后的s_instance不要再加锁了,提高效率
//		{
//			static std::mutex mut;
//			unique_lock<mutex> uniqueLock(mut);
//			if (s_instance==nullptr)
//			{
//				s_instance = new Single();
//				static GC gc; // 析沟中释放单例对象
//			}
//		}
//		return s_instance;
//	}
	// 单例,方式二(std::call_once(std::once_flag, func)): call_once也会互斥,比手动写mutex效率感觉要低一些?
	static Single *getInstance()
	{
		if (s_instance==nullptr)
		{
			static std::once_flag flag; // 标量,实际是一个结构体,表示只调用一次
			std::call_once(flag, create);
		}
		return s_instance;
	}
};
Single *Single::s_instance = nullptr;

int main_2_6_7(int argc, char *argv[])
{
	Single *single = Single::getInstance();
	Single *s2 = Single::getInstance();

	// std::call_once(std::once_flag, func) 函数模板,c++11引入,作用:多次执行此代码的情况下,只会调用一次func函数(当第一次执行func后,once_flag会被改为已调用状态)

	return 0;
}

6_8_condition_wait_notify.cpp

#include "hjcommon.hpp"
#include <thread>
#include <mutex>
#include <list>
#include <condition_variable>

using namespace std;
HJ_NS_USING

// notify_one() 演示
class C
{
public:
	void write()
	{
		for(int i=0; i<100000; ++i)
		{
			std::unique_lock<mutex> uniqueLock(m_mutex);
			cout << "notify_one   write : " << i << endl;
			m_list.push_back(i);
			m_cond.notify_one(); // 尝试唤醒一个wait(),此时若无wait(),则函数直接返回,不会进行其他任何处理
		}

		std::unique_lock<mutex> uniqueLock(m_mutex);
		isWriteFinish = true;
		m_cond.notify_all();
	}
	void read()
	{
		while(true)
		{
			std::unique_lock<mutex> uniqueLock(m_mutex);
			// 等待,如果lambda返回false,wait()将解锁互斥,并在此行代码堵塞,堵塞到其他线程调用m_cond.notify_one()函数唤醒为止,
			//			此时wait()会不断尝试去锁住互斥,若无法锁住那么会继续阻塞等待下次唤醒,
			//			若成功锁住互斥,那么wait()会再次执行lambda,若此时还是返回false,则重复上述步骤,
			//			若此时返回true,那么接着执行下行代码
			//      如果lambda返回true,那么wait()直接返回,接着执行下行代码
			m_cond.wait(uniqueLock, [this] { // 第二个参数只要是可调用对象即可
				return !m_list.empty() || isWriteFinish;
			});
//			m_cond.wait(uniqueLock); // 与m_cond.wait(uniqueLock, lambda)中lambda返回false效果一样,区别是只要被唤醒,就会再次尝试锁住互斥,锁住后接着执行下行代码

			if (!m_list.empty())
			{
				int var = m_list.front();
				m_list.pop_front();
				cout << "notify_one   read : " << var << endl;
			}
			else
				if (isWriteFinish) break;
			uniqueLock.unlock(); // 执行无关代码时可以提前解锁,让其他线程继续执行
			// ... 无关代码
		}
	}

private:
	std::list<int> m_list;
	std::mutex m_mutex;
	bool isWriteFinish = false;

	std::condition_variable m_cond;
};

int main_2_6_8_1(int argc, char *atgv[])
{
	// notify_one() 演示
	C a;
	thread writeThread(&C::write, &a);
	thread readThread(&C::read, &a);
	writeThread.join();
	readThread.join();

	// 条件变量:std::condition_variable、wait()、notify_one()
	// std::condition_variable 实际上是一个类,需要包含 #include <condition_variable>
	// void condition_variable.wait(...)
	// bool/cv_status condition_variable.wait_for(...) // cv_status 枚举值,超时或未超时
	// bool/cv_status condition_variable.wait_until(...)
	// notify_one() 一次唤醒一个condition_variable.wait()
	// notify_all() 唤醒所有condition_variable.wait()

	condition_variable cond;
	mutex mu;
	unique_lock<mutex> ul(mu);
	bool is = cond.wait_for(ul, std::chrono::seconds(1), []{
		cout << "wait_for." << endl;
		return false;
	}); // 与wait()类似,区别是如果在阻塞duration时长后,若没有被notify,那么此时会锁住互斥,接着执行lambda,若lambda返回false,不会继续阻塞,而是继续执行后续代码
	// condition_variable.wait_until(...) 与wait_for()类似,区别是wait_for是等待一定时长,wait_until是等待到某个时间点

	cout << "end." << endl;
	return 0;
}

6_8_生产者消费者.cpp

#include "hjcommon.hpp"
#include <queue>
#include <thread>
#include <mutex>
#include <memory>
#include <condition_variable>

using namespace std;
HJ_NS_USING

// 数据类
class Writer;
class Consumer;
class Data
{
public:
	queue<int> m_dataQueue;
	std::mutex m_mutex;
	std::condition_variable m_cond;
	int m_writerCount = 0;
	int m_consumerCount = 0;
	bool isAllWrited = false;

	~Data() { cout << "~Data" << endl; }

	void addWriter(unique_ptr<Writer> writer)
	{
		++m_writerCount;
		m_writerQueue.push(std::move(writer));
	}
	void addComsumer(unique_ptr<Consumer> consumer)
	{
		++m_consumerCount;
		m_comsumerQueue.push(std::move(consumer));
	}

private:
	queue<unique_ptr<Writer>> m_writerQueue;
	queue<unique_ptr<Consumer>> m_comsumerQueue;
};

// 生产者
class Writer
{
public:
	Writer(Data &data, int index) : m_data(data), m_index(index) {}
	~Writer() { cout << "~Writer" << m_index << endl; }

	void write()
	{
		int start = m_index*m_len;
		int end = (m_index+1)*m_len;
		for(int i=start; i<end; ++i)
		{
			unique_lock<mutex> uniqueLock(m_data.m_mutex);
			m_data.m_dataQueue.push(i);
			cout << "Writer" << m_index << " write : " << i << ", threadId=" << this_thread::get_id() << endl;
			m_data.m_cond.notify_one(); // 这里用notify_all()效果一样的
		}
		cout << "Writer" << m_index << " finished" << ", threadId=" << this_thread::get_id() << endl;

		// 结束所有consume线程死循环结
		unique_lock<mutex> uniqueLock(m_data.m_mutex);
		++m_wrtierCount;
		if (m_wrtierCount==m_data.m_writerCount)
		{
			m_data.isAllWrited = true;
			m_data.m_cond.notify_all(); // 这里必须用notify_all()了,因为有多个线程wait()了
		}
	}

private:
	Data &m_data;
	int m_index;
	const int m_len = 100000;
	static int m_wrtierCount;
};
int Writer::m_wrtierCount = 0;

// 消费者,一条数据只允许一个消费者消费
class Consumer
{
public:
	Consumer(Data &data, int index) : m_data(data), m_index(index) {}
	~Consumer() { cout << "~Consumer" << m_index << endl; }

	void consume()
	{
		while(true)
		{
			unique_lock<mutex> uniqueLock(m_data.m_mutex);
			m_data.m_cond.wait(uniqueLock, [this]{
				return !m_data.m_dataQueue.empty() || m_data.isAllWrited;
			});
			if (!m_data.m_dataQueue.empty())
			{
				int data = m_data.m_dataQueue.front();
				m_data.m_dataQueue.pop();
				cout << "Consumer" << m_index << " consume : " << data << ", threadId=" << this_thread::get_id() << endl;
			}
			else
			{
				if (m_data.isAllWrited) break;
			}
		}
	}

private:
	Data &m_data;
	int m_index;
};

int main_2_6_8_2(int argc, char *argv[])
{
	// 生产者消费者模式 模拟(多个生产者线程,多个消费者线程)
	Data data;
	vector<thread> threadVec;
	for (int i=0; i<10; ++i)
	{
		unique_ptr<Writer> p = make_unique<Writer>(data, i);
		threadVec.push_back(thread(&Writer::write, p.get())); // 注意这里用的p.get(),传递的是对象指针,因为用的是unique_ptr,不要thread传参时发生拷贝构造
		data.addWriter(std::move(p));
	}
	for (int i=0; i<5; ++i)
	{
		unique_ptr<Consumer> p = make_unique<Consumer>(data, i);
		threadVec.push_back(thread(&Consumer::consume, p.get()));
		data.addComsumer(std::move(p));
	}
	for (auto it=threadVec.begin(); it!=threadVec.end(); ++it)
	{
		it->join();
	}

	cout << "end." << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值