c++并发编程(三)——在线程间共享数据 mutex

c++标准提供的保护共享数据的最基本机制是互斥元(mutex)。

std::mutex my_mutex;

void fun() {
	
	my_mutex.lock();        //互斥元加锁
	do_something();
	my_mutex.unlock();      //互斥元解锁

}

void fun2() {
	std::lock_guard<std::mutex> my_lock(my_mutex);    //使用lock_guard进行包装,在构造时锁定互斥元,在析构时解锁互斥元
	do_something();
}

一个线程安全栈的类定义:

#include <memory>
#include <mutex>
#include <stack>

struct empty_stack: std::exception
{
  const char* what() const throw() {
    return "empty stack!";
  };
};

template<typename T>
class threadsafe_stack
{
private:
   std::stack<T>data_;
   mutable MutexLock lock_;
public:
    threadsafe_stack():data_(std::stack<int>()) {}
    threadsafe_stack()(const threadsafe_stack& other) {
      LockGuard<MutexLock>(&other.lock_);
      data_ = other.data_ ; // 
   }
threadsafe_stack & operator=(const threadsafe_stack&)= delete;

void push(T new_value) {
   LockGuard<MutexLock> lock(&lock_);
   data_.push(new_value);
}

std::shared_ptr<T> pop() {
   LockGuard<MutexLock> lock (&lock_);
   if (data_.empty()) throw empty_stack(); // 在调用pop 前, 检查栈是否为空 

   std:: shared_ptr <T> const res(std::make_shared<T>(data_.top()));//在修改栈前,分配出返回值
   data_.pop();
   return res;
}

 void pop(T& value)
  {
    LockGuard<MutexLock> lock(&lock_);
    if(data_.empty()) throw empty_stack();

    value=data_.top();
    data_.pop();
  }

  bool empty() const
  {
    LockGuard<MutexLock> lock(&lock_);
    return data_.empty();
  }
};

使用std::lock同时给多个互斥元加锁:

std::mutex m1;
std::mutex m2;

std::lock(m1,m2);
std::lock_guard<std::mutex> lock_a(m1,std::adopt_lock);  //std::adopt_lock表明已上锁
std::lock_guard<std::mutex> lock_b(m2,std::adopt_lock);

避免死锁

  1. 避免嵌套锁
  2. 在持有锁的时候,避免调用用户提供的代码
  3. 以固定的顺序获取锁
  4. 使用锁层次
//一个简单的分层次互斥元
class hierarchical_mutex {
private:
	std::mutex internal_mutex;
	std::mutex data_mutex;
	unsigned long const hierarchy_value;
	// 保存上一次的层次值,该锁不能重入,所以只需要一个简单数据类型来保存
	unsigned long previous_hierarchy_value;
	// 当前层次值
	static thread_local unsigned long this_thread_hierarchy_value;
	void check_for_hierarchy_violation() 
	{
		// 当前线程锁定了更低等级的或者是同等级的锁
		if (this_thread_hierarchy_value <= hierarchy_value)
		{
			throw std::logic_error("mutex hierarchy violated");
		}
	}
	void update_hierarchy_value() 
	{
		// 保存当前层次值
		previous_hierarchy_value = this_thread_hierarchy_value; 
		// 改变当前层次值
		this_thread_hierarchy_value = hierarchy_value; 
	}
public:
	explicit hierarchical_mutex(unsigned long value) 
		:hierarchy_value(value),previous_hierarchy_value(0){}
	void lock()
	{
		check_for_hierarchy_violation();
		internal_mutex.lock();
		lock_guard<std::mutex> lock(data_mutex);
		update_hierarchy_value();
	}
	void unlock()
	{
		internal_mutex.unlock();
		lock_guard<std::mutex> lock(data_mutex);
		this_thread_hierarchy_value = previous_hierarchy_value;
		
	}
	bool try_lock() 
	{
		check_for_hierarchy_violation();
		if (!internal_mutex.try_lock())
			return false;
		lock_guard<std::mutex> lock(data_mutex);
		update_hierarchy_value();
		return true; 
	}
};
thread_local unsigned long hierarchical_mutex::this_thread_hierarchy_value = ULONG_MAX;

使用std::unique_lock灵活锁定

std::unique_lock同std::lock_guard功能类似但它更加灵活 。 
它在lock_guard的基础上还能: 
—— 没有关联互斥体时创建 
—— 没有锁定的互斥体时创建 
—— 显式和重复设置或释放关联互斥锁 
—— 移动互斥体 move 
—— 尝试锁定互斥体 
—— 延迟锁定关联互斥体

std::mutex m;
std::unqiue_lock<std::mutex> my_lock(m,std::defer_lock);   //使用std::defer_lock保留互斥元未锁定
my_lock.lock();      //加锁
my_lock.unlock();    //解锁

使用std::call_once使函数只被调用一次

std::once_flag f1;

void fun() {
	
	std::cout << "hello call_once" << std::endl;

}

void fun_once() {
	std::call_once(f1, fun);
}

int main() {

	std::vector<std::thread> t;
	for (int i = 0; i < 10; i++) {
		//t.push_back(std::thread(fun));          
		t.push_back(std::thread(fun_once));       //只调用一次
		t[i].join();
	}
	system("pause");
	return 0;
}

读写锁:允许同一时刻对共享区域执行多个“读”操作,或者一个“写”操作,c++标准库并未给出实现

递归锁:可以多次lock,使用std::recursive_mutex(类似mutex用法)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值