仅锁定两个可能的互斥锁之一

Lock only one of two possible mutexes

本文关键字:锁定 两个      更新时间:2023-10-16

我有一个多线程C++程序,可以模拟汽车修理厂。基本上,car在这里是一个线程,station是一个资源。它的工作原理是这样的:汽车进入一个车间,它有一个车站列表(只是整数(,它必须访问,才能得到维修。有3种类型的车站:

  • 1x2站-1站可一次修理2辆车
  • 1x1站-1站可一次修理1辆车
  • 2x1 工作站 - 完成工作需要 2 个工作站

最后两种类型对我来说很容易,因为在1x1类型中,我只需将互斥锁锁定在station上,其他线程必须等待。在2x1类型上,我只是在两个站点上进行std::lock以避免死锁等。

问题出在第一种类型上。让我们想象一下,一次修理两辆车意味着一辆车在车站的左侧,另一辆车在右侧(我也必须用ncurses来绘制这种情况(。所以我想到了像这样为1x2类型实现一个站:

class station1x2 {
public:
std::mutex r_mutex;
std::mutex l_mutex;
}

所以我想锁定r_mutexl_mutex,所以有 4 种可能的情况:

  • 他们两个都没有锁定,我锁定了他们中的任何一个
  • 右边的锁定,我锁定左边
  • 左边的被锁住,我锁右边的
  • 他们两个都被锁住了,我等着

这里的问题是:C++是否有一种机制可以只锁定给定互斥锁中的一个?(就像我为我的r_mutex和l_mutex赋予某些功能,它选择未锁定的函数并为我锁定它(。

互斥锁在这里不是正确的同步原语。这可以通过信号量(基本上是 0-n 原语,互斥锁为 0-1(来完成,但标准库中没有信号量。

但是,您可以在此处使用一个条件变量。您将需要:

  • 指示"车站中有可用空间"的条件变量
  • 表示工作站中可用空间的计数器(或其他方式,例如两个布尔值(
  • 保护这些的互斥锁

进入车站时,锁定互斥锁,看看是否有可用空间。如果有,请占用一个,释放互斥锁,然后进行维修。如果两者都已满,请等待条件变量(这将释放互斥锁(。

完成修复后,锁定互斥锁,将空间标记为可用,释放互斥锁并通知条件变量(因为现在有可用空间(。

在代码中:

class station1x2 {
public:
std::mutex mutex;
std::condition_variable cond;
int freeSpaces;
void enter() {
std::unique_lock<std::mutex> l(mutex);
cond.wait(l, [&]() { return freeSpaces > 0; }
--freeSpaces;
}
void exit() {
{
std::unique_lock<std::mutex> l(mutex);
++freeSpaces;
}
cond.notify_one();
}
}

在您的情况下,我会使用try_lock方法。如果锁定可能,此方法返回true(并锁定互斥锁(,否则false返回(已锁定互斥锁(。

if (!r_mutex.try_lock() && !l_mutex.try_lock())
std::cout << "All mutexes already locked" << std::endl;