C++ 多线程的错误和如何避免(7)

要以相同顺序获取多个锁

多线程在加锁解锁时,可能会出现死锁问题,比如,

线程 1 在加锁 mutex A 后,继续尝试获取 mutex B,而 mutex B 已经被线程 2 获取,而线程 2 在等待获取 mutex A,mutex B 只有线程 2 获取 mutex  A 后才能解锁,

这就导致线程 1 和线程 2 互相等待锁,而这一操作就是死锁情况,容易导致程序挂起。

C++ 多线程的错误和如何避免(7)

 

 使用代码模拟死锁场景:

#include <iostream>
#include <string>
#include <thread>
#include <mutex>

using namespace std;

std::mutex muA;
std::mutex muB;

void CallHome_AB(string message)
{
  muA.lock();
  //Some additional processing 
  std::this_thread::sleep_for(std::chrono::milliseconds(100));
  muB.lock();

  cout << "Thread " << this_thread::get_id() << " says " << message << endl;

  muB.unlock();
  muA.unlock();
}

void CallHome_BA(string message)
{
  muB.lock();
  //Some additional processing 
  std::this_thread::sleep_for(std::chrono::milliseconds(100));
  muA.lock();

  cout << "Thread " << this_thread::get_id() << " says " << message << endl;

  muA.unlock();
  muB.unlock();
}

int main()
{
  thread t1(CallHome_AB, "Hello from Jupiter");
  thread t2(CallHome_BA, "Hello from Pluto");

  t1.join();
  t2.join();

  return 0;
}  

运行后,会发现控制台没有打印任何字符串,因为两个线程都尝试获取对方的锁,导致了死锁

如何解决?

最好的办法就是所有的锁都可以以相同的顺序获得,比如线程 1 顺序获得 mutex A 和 mutex B,再释放 mutex B 和 mutex A,线程 2 也顺序获得 mutex A 和 B,再顺序释放

std::mutex muA;
std::mutex muB;

void CallHome_AB(string message) {
  muA.lock();
  // Some additional processing
  std::this_thread::sleep_for(std::chrono::milliseconds(100));
  muB.lock();

  cout << "Thread " << this_thread::get_id() << " says " << message << endl;

  muB.unlock();
  muA.unlock();
}

void CallHome_BA(string message) {
  muA.lock();
  // Some additional processing
  std::this_thread::sleep_for(std::chrono::milliseconds(100));
  muB.lock();

  cout << "Thread " << this_thread::get_id() << " says " << message << endl;

  muB.unlock();
  muA.unlock();
}

当然目前也有封装好的 C++ 函数来同时获得两个锁,如下

std::scoped_lock lock{muA, muB};

The class scoped_lock is a mutex wrapper that provides a convenient RAII-style mechanism for owning one or more mutexes for the duration of a scoped block.

When a scoped_lock object is created, it attempts to take ownership of the mutexes it is given. When control leaves the scope in which the scoped_lock object was created, the scoped_lock is destructed and the mutexes are released. If several mutexes are given, deadlock avoidance algorithm is used as if by std::lock.

或者我们也可以用 std::timed_mutex 来解决这个问题,当超过一定时间后自动释放锁

The timed_mutex class is a synchronization primitive that can be used to protect shared data from being simultaneously accessed by multiple threads.

 

原文链接: https://www.cnblogs.com/strive-sun/p/16291767.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    C++ 多线程的错误和如何避免(7)

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/404520

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月25日 下午4:36
下一篇 2023年4月25日 下午4:36

相关推荐