您当前的位置: 首页 >  c++

龚建波

暂无认证

  • 2浏览

    0关注

    313博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

C++ std::mutex互斥元/锁

龚建波 发布时间:2019-08-25 00:09:55 ,浏览量:2

0.前言

将多线程作为并行的关键优点之一,在于它们之间简单直接地共享数据的能力。但当多个线程修改同一数据时,就很容易因为竞争而导致错误的执行结果。若所有线程只是进行读取操作,就没有问题。

1.认识std::mutex

由C++标准提供的保护共享数据的最基本机制是互斥元/锁(mutex)(读缪特克斯)。在访问共享数据之前,锁定(lock)与该数据相关的互斥元,访问完成后,解锁(unlock)该互斥元。线程库会确保一个线程锁定某个互斥元后,其他试图锁定该互斥元的线程必须等待,直到之前的线程解锁。(如果需要递归锁定,可以使用 recursive_mutex )

可以通过在线手册查看该类接口 https://zh.cppreference.com/w/cpp/thread/mutex ,除了lock和unlock,还有一个try_lock方法:尝试锁定互斥,若互斥不可用则返回。需要注意的是,不要随意将受保护数据的指针或引用传递到锁的范围之外。

#include 

std::mutex mtx;
int num;

void set(int i) {
	mtx.lock();
	num = i;
	mtx.unlock();
}

int get() {
	mtx.lock();
	const int temp = num;
	mtx.unlock();
	return temp;
}
2.认识std::lock_guard

标准C++库还提供了std::lock_guard类模板,在构造时锁定给定的互斥元,析构时将互斥元解锁,从而保证锁定的互斥元始终被正确解锁。

#include 

std::mutex mtx;
int num;

void set(int i) {
	std::lock_guard guard(mtx);
	num = i;
}

int get() {
	std::lock_guard guard(mtx);
	return num;
}

该类模板有两个构造函数:

 explicit lock_guard( mutex_type& m ); 等效地调用 m.lock() ,若 m 不是递归互斥,且当前线程已占有 m 则行为未定义。

 lock_guard( mutex_type& m, std::adopt_lock_t t ); 获得互斥 m 的所有权而不试图锁定它。若当前线程不占有 m 则行为未定义。

如果单单使用mutex和lock_guard还是比较简单的,毕竟接口就那么几个。下面的例子中,我构造了一个队列,一个线程写入操作,两个线程读取操作。

#include 
#include 
#include 
#include 
#include 
//pair
#include 

template
class ThreadQueue
{
public:
	ThreadQueue() {}
	~ThreadQueue() {}

	void inqueue(const T& item) {
		std::lock_guard guard(dataMutex);
		//dataMutex.lock();
		dataQueue.push(item);
		//dataMutex.unlock();
	}

	std::pair dequeue() {
		std::lock_guard guard(dataMutex);
		//dataMutex.lock();
		bool is_valid = false;
		T item;
		if (!dataQueue.empty()) {
			is_valid = true;
			item = dataQueue.front();
			dataQueue.pop();
		}
		//dataMutex.unlock();
		return std::make_pair(is_valid, item);
	}

	bool notEmpty() const {
		return (!dataQueue.empty());
	}

private:
	std::mutex dataMutex;
	std::queue dataQueue;
};

int main()
{
	ThreadQueue my_queue;
	int counter = 0;
	bool working = true;
	std::thread write_thread([&]() {
		while (working) {
			std::this_thread::sleep_for(std::chrono::milliseconds(100));
			my_queue.inqueue(++counter);
			std::cerr             
关注
打赏
1655829268
查看更多评论
0.2035s