多线程-数据共享问题
Posted zhiminzeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程-数据共享问题相关的知识,希望对你有一定的参考价值。
一、基本概念
1、互斥量(mutex)
互斥量:是个类对象(可以理解为一把锁),多个线程尝试用lock()成员函数来加锁这把锁,只有一个线程能锁定成功(成功的标志是lock()函数能够返回,返回不了说明没有锁成功)
2、死锁
死锁:一般是两个或两个以上的互斥量,在两个或多个地方上锁的顺序不一致导致的互相等待的情况
死锁解决方法:保证每个地方,互斥量上锁的顺序一致
二、样例
1、多线程加锁的例子
class MyClass{ // 模拟给一个消息队列发消息和处理消息 public: void WriteMessage() // 模拟发消息,也就是往消息队列中写 { for (int i = 0; i < 10000; ++i) { cout << "插入一个元素:" << i << endl; m_mutex.lock(); // lock() 与 unlock() 要成对使用 m_messages.push_back(i); m_mutex.unlock(); } } //void ReadMessage() // 模拟处理消息队列中的消息,从中读,也删除 //{ // for (int i = 0; i < 10000; ++i) // { // if (!m_messages.empty()) // 用到共享数据m_messages 的地方都要加锁 // { // int i = m_messages.front(); // 用到共享数据m_messages 的地方都要加锁 // cout << "读取的数据为:" << i << endl; // 此处不需要加锁,只加锁需要加锁的部分,提高程序效率 // m_messages.pop_front(); // 用到共享数据m_messages 的地方都要加锁 // } // else // { // cout << "目前消息队列为空" << i << endl; // } // } //} // 上面的函数优化后的结果 // 把需要加锁的代码专门提取出来 // 只对需要加锁的代码加锁,操作共享数据的部分 bool IsMessagesListEmpty(int& iCount) { m_mutex.lock(); if(!m_messages.empty()) { iCount = m_messages.front(); m_messages.pop_front(); m_mutex.unlock(); // 每条分支语句都要unlock return true; } m_mutex.unlock(); // 每条分支语句都要unlock return false; } void ReadMessage() // 模拟处理消息队列中的消息,从中读,也删除 { int iCount = 0; for (int i = 0; i < 10000; ++i) { if (IsMessagesListEmpty(i)) { cout << "读取的数据为:" << i << endl; } else { cout << "目前消息队列为空" << i << endl; } } } private: list<int> m_messages; // 模拟消息队列 mutex m_mutex; // 创建一个互斥量成员对象 }; int main() { MyClass ele; std::thread writeThread(&MyClass::WriteMessage, &ele); // std::thread readThread(&MyClass::ReadMessage, &ele); // readThread.join(); writeThread.join(); cout << "主线程" << endl; system("pause"); return 0; }
2、lock_guard
//std::lock_guard 相当于lock和unlock std::lock_guard<std::mutex> myLockGuard(m_mutex); // myLockGuard构造的时候执行mutex::lock // myLockGuard析构的时候执行mutex::unlock // 可以通过加 {} 来控制lock_guard 的生存周期,从而达到随时加锁,随时解锁的目的
3、std::lock
// 解决死锁的方法,保证上锁的顺序一致 // 也可以用std::lock() 来对多个锁进行加锁 // std::lock() 可以同时锁住两个或两个以上的互斥量 // 它不存在在多线程中,因为锁的顺序问题,而导致的死锁问题 // 要么其中的互斥量都锁住,要么都没锁住,不会锁住其中一个,而去等另外一个 // 也就是说,如果其中有一个锁已经被锁住了,它需要等所有的锁都能上锁的状态,才能加锁,继续往下执行 // 示例: std::lock(m_mutex1, m_mutex2) // 上锁一起上 m_mutex1.unlock(); // 解锁还是需要自己解锁 m_mutex2.unlock();
4、结合std::lock() 和lock_guard
// 结合lock_guard 和 std::lock 达到不需要手动unlock() 的效果 std::lock(m_mutex1, m_mutex2) std::lock_guard<std::mutex> myLockGuard(m_mutex1, std::adopt_lock); std::lock_guard<std::mutex> myLockGuard(m_mutex2, std::adopt_lock); // std::adopt_lock 的作用是让 lock_guard 在构造的时候,不执行lock() // 因为在std::lock()中已经执行了lock()
以上是关于多线程-数据共享问题的主要内容,如果未能解决你的问题,请参考以下文章