C++线程学习二(互斥量中其他类模板的使用)

   1、unique_lock介绍

        (1)unique_lock是个类模板,它比lock_guard灵活很多,但是效率会低一些,占用内存较多;一般推荐使用lock_guard(lock_guard取代了mutex中的lock()和unlock());


2、unique_lock<std::mutex> 使用的灵活性

2.1 unique_lock与lock_guard使用对比


            std::lock_guard<std::mutex> uniqueLock(m_Mutex, std::adopt_lock);   
            // adopt_lock标记作用,表示互斥量已经被lock了(互斥量必须提前lock,否则会出现异常),lock_guard不需要在构造函数中lock这个互斥量
            
            std::unique_lock<std::mutex>  uniqueLock(m_Mutex, std::adopt_lock);
            // unique_lock也可以带adopt_lock,含义相同

// unique_lock()使用的灵活性
std::unique_lock<std::mutex> uniqueLock(m_Mutex,std::defer_lock); // 没有加锁的m_Mutex

m_Mutex.lock();  // 多次重复调用时需要自己解锁,后再加锁	
// 处理共享内存		
m_Mutex.unlock();

		
// 处理非共享内存

		
m_Mutex.lock();		
// 再次处理共享内存
m_Mutex.unlock();

    
3、unique_lock其他参数


            std::unique_lock<std::mutex>  uniqueLock(m_Mutex, std::try_to_lock);   // 参数使用范例
            try_to_lock参数,类似于lock()去锁定这个互斥量,如果没有锁成功,就会立即返回,不会出现阻塞现象,使用try_to_lock的前提是不能在前面使用lock(),添加后需要unlock
            
            std::unique_lock<std::mutex> 
            std::uniqueLock(m_Mutex, std::defect_lock);   // 参数使用范例
            defect_lock参数,前提是不能在前面添加lock,否则会报异常;defer_lock作用是,初始化一个未加锁的mutex

// 存数据
void inMsgRecvQueue()
{
  for (int i = 0; i < 1000; i++)
  {
	// 添加作用域
	{		
	  std::unique_lock<std::mutex> uniqueLock(m_Mutex, std::try_to_lock);
	  if (uniqueLock.owns_lock())
	  {
	  	m_RecvQueue.push_back(i);
	  }
	  else
	  {
	  	cout << "没有获得锁" << endl;
	  }
	}

	  // doSomething
	  // ...
	}	
}

 

4、unipue_lock成员函数


        lock,unlock   加锁,解锁
        try_lock,尝试给互斥量加锁,如果拿不到锁,返回false,否则返回true,不会导致函数阻塞
        release,返回它所管理的mutex对象指针,并释放所有权,使unipue_lock与mutex不再有关系
        如果mutex对象处于加锁状态,此指针负责解锁

bool outMsgQueue(int &num)
{

// try_lock()用法		
  std::unique_lock<std::mutex> uniqueLock(m_Mutex, std::defer_lock); // 没有加锁的m_Mutex
  if (uniqueLock.try_lock() == true)
  {
    if (!m_RecvQueue.empty())
	{
	  num = m_RecvQueue.front();	// 返回第一个元素,但是不检查元素是否存在;
	  m_RecvQueue.pop_front();				// 移除第一个元素但不反回
	  //m_Mutex.unlock();
	  return true;
	}
  }
  else
  {
    cout << "没有获得锁" << endl;
    return false;
  }
		
}

// 取数据
void outMsgRecvQueue()
{
  int num;
  for (int i = 0; i < 1000; i++)
  {
      if (outMsgQueue(num))
	{
	  cout << "delet one data" << num << endl;
	}
	else
	{
	  cout << "outMsgRecvQueue no data" << endl;
	}
  }

cout << "end" << endl;
	
}

5、unipue_lock所有权的传递

    std::unique_lock<std::mutex> uniqueLock(m_Mutex, std::defer_lock)  
    所有权:uniqueLock拥有m_Mutex的所有权
    unique_lock的mutex对象的所有权可以转移,但是不能复制

bool outMsgQueue(int &num)
{

  std::unique_lock<std::mutex> uniqueLock(m_Mutex, std::defer_lock);
  //std::unique_lock<std::mutex> uniqueLock1(m_Mutex, std::defer_lock);   // 此时uniqueLock1复制所有权是非法的
  std::unique_lock<std::mutex> uniqueLock2( std::move(uniqueLock));   // 转移所有权是合法的
  if (!m_RecvQueue.empty())
  {
    num = m_RecvQueue.front();			// 返回第一个元素,但是不检查元素是否存在;
    m_RecvQueue.pop_front();			// 移除第一个元素但不返回
    return true;
  }	
  return false;
}

6、线程锁使用注意

       线程锁,锁住的代码段要尽可能少,这样代码执行效率会高;锁定范围太高,代码执行效率低。要合理的控制互斥锁的锁定范围

 

 

#include <iostream>
#include <thread>
#include <list>
#include <mutex>
using namespace std;
class dataShare
{
public:
  std::unique_lock<std::mutex> rtn_unique_lock()
  {
    std::unique_lock<std::mutex> tempGuard(m_Mutex);
    return tempGuard;
  }
  dataShare()
  {
  }
  ~dataShare()
  {
  }
  // 存数据
  void inMsgRecvQueue()
  {
    for (int i = 0; i < 1000; i++)
    {		
       // 添加作用域
       {
        std::unique_lock<std::mutex> uniqueLock = rtn_unique_lock();
        if (uniqueLock.owns_lock())
        {
           m_RecvQueue.push_back(i);
        }
        else
        {
          cout << "没有获得锁" << endl;
        }
    }

    // doSomething
    // ...
    }
  }
  bool outMsgQueue(int &num)
  {
    std::unique_lock<std::mutex> uniqueLock(m_Mutex, std::defer_lock);
    //std::unique_lock<std::mutex> uniqueLock1(m_Mutex, std::defer_lock);   // 此时uniqueLock1复制所有权是非法的
    std::unique_lock<std::mutex> uniqueLock2( std::move(uniqueLock));   // 转移所有权是合法的
    if (!m_RecvQueue.empty())
	{
	  num = m_RecvQueue.front();			// 返回第一个元素,但是不检查元素是否存在;
	  m_RecvQueue.pop_front();				// 移除第一个元素但不反回
	  return true;
	}		
	return false;
  }

  // 取数据
  void outMsgRecvQueue()
  {
    int num;
	for (int i = 0; i < 1000; i++)
	{
	  if (outMsgQueue(num))
	  {
		cout << "delet one data" << num << endl;
	  }
	  else
	  {
		cout << "outMsgRecvQueue no data" << endl;
	  }
	}
	cout << "end" << endl;
  }
private:
  std::list<int> m_RecvQueue;
  //互斥量
  std::mutex m_Mutex;
};

int main()
{
  dataShare datas;
  std::thread inMsgObj(&dataShare::inMsgRecvQueue, &datas);
  std::thread outMsgObj(&dataShare::outMsgRecvQueue, &datas);
  inMsgObj.join();
  outMsgObj.join();

  system("pause");
  return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值