只锁定两个可能的互斥量之一
Lock only one of two possible mutexes
我有一个模拟汽车车间的多线程 C++ 程序。基本上 car
在这里是一个线程,station
是一个资源。它是这样工作的:汽车进入一个车间,它有一个站点列表(只是整数),它必须访问,才能得到修理。有 3 种类型的电台:
- 1x2 station - 1 station 可以同时修理 2 辆汽车
- 1x1 station - 1 station 一次可以修理 1 辆车
- 2x1 站点 - 完成工作需要 2 个站点
最后两种类型对我来说很容易,因为在 1x1
类型中我只是将互斥锁锁定在 station
上,其他线程必须等待。在 2x1
类型上,我只是在两个站上使用 std::lock
以避免死锁等
问题出在第一种类型上。让我们想象一下,同时修理两辆车意味着一辆车在车站的左手边,另一辆车在车站的右手边(我将不得不用 ncurses
绘制这种情况)。所以我考虑为 1x2
类型实现一个站点,如下所示:
class station1x2 {
public:
std::mutex r_mutex;
std::mutex l_mutex;
}
所以我想锁定 r_mutex
或 l_mutex
,所以有 4 种可能的情况:
- 两个都没有锁,我锁哪个
- 右边一个锁了,我锁左边一个
- 左一个锁了,我锁右一个
- 两个都锁了,我等
这里的问题是:在 C++ 中是否有一种机制可以只锁定一个给定的互斥体? (就像我给 r_mutex 和 l_mutex 一些功能,它选择未锁定的功能并为我锁定)。
对于您的情况,我会使用 try_lock
方法。此方法 returns true
(并锁定互斥量)如果可以锁定,false
否则(已锁定互斥量)。
if (!r_mutex.try_lock() && !l_mutex.try_lock())
std::cout << "All mutexes already locked" << std::endl;
互斥体在这里不是正确的同步原语。这可以通过 semaphore(基本上是 0-n 原语,其中互斥锁为 0-1)来完成,但标准库中没有信号量。
不过,这里有一个条件变量,您可以在此处使用它。您将需要:
- 用于发出信号的条件变量 "there's free space in the station"
- 一个计数器(或其他方式,例如两个布尔值)表示站点中的空闲 spaces
- 保护这些的互斥体
进站时,锁上互斥锁,看看有没有空闲space。如果有,占用一个,释放互斥量,并得到修复。如果两者都已满,则等待条件变量(这将释放互斥量)。
修复完成后,锁定互斥锁,将您的 space 标记为空闲,释放互斥锁并通知条件变量(因为现在有空闲的 space)。
在代码中:
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();
}
}
我有一个模拟汽车车间的多线程 C++ 程序。基本上 car
在这里是一个线程,station
是一个资源。它是这样工作的:汽车进入一个车间,它有一个站点列表(只是整数),它必须访问,才能得到修理。有 3 种类型的电台:
- 1x2 station - 1 station 可以同时修理 2 辆汽车
- 1x1 station - 1 station 一次可以修理 1 辆车
- 2x1 站点 - 完成工作需要 2 个站点
最后两种类型对我来说很容易,因为在 1x1
类型中我只是将互斥锁锁定在 station
上,其他线程必须等待。在 2x1
类型上,我只是在两个站上使用 std::lock
以避免死锁等
问题出在第一种类型上。让我们想象一下,同时修理两辆车意味着一辆车在车站的左手边,另一辆车在车站的右手边(我将不得不用 ncurses
绘制这种情况)。所以我考虑为 1x2
类型实现一个站点,如下所示:
class station1x2 {
public:
std::mutex r_mutex;
std::mutex l_mutex;
}
所以我想锁定 r_mutex
或 l_mutex
,所以有 4 种可能的情况:
- 两个都没有锁,我锁哪个
- 右边一个锁了,我锁左边一个
- 左一个锁了,我锁右一个
- 两个都锁了,我等
这里的问题是:在 C++ 中是否有一种机制可以只锁定一个给定的互斥体? (就像我给 r_mutex 和 l_mutex 一些功能,它选择未锁定的功能并为我锁定)。
对于您的情况,我会使用 try_lock
方法。此方法 returns true
(并锁定互斥量)如果可以锁定,false
否则(已锁定互斥量)。
if (!r_mutex.try_lock() && !l_mutex.try_lock())
std::cout << "All mutexes already locked" << std::endl;
互斥体在这里不是正确的同步原语。这可以通过 semaphore(基本上是 0-n 原语,其中互斥锁为 0-1)来完成,但标准库中没有信号量。
不过,这里有一个条件变量,您可以在此处使用它。您将需要:
- 用于发出信号的条件变量 "there's free space in the station"
- 一个计数器(或其他方式,例如两个布尔值)表示站点中的空闲 spaces
- 保护这些的互斥体
进站时,锁上互斥锁,看看有没有空闲space。如果有,占用一个,释放互斥量,并得到修复。如果两者都已满,则等待条件变量(这将释放互斥量)。
修复完成后,锁定互斥锁,将您的 space 标记为空闲,释放互斥锁并通知条件变量(因为现在有空闲的 space)。
在代码中:
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();
}
}