同时锁定两个互斥量
Lock two mutex at same time
我正在尝试实现多输入多输出线程间通道 class。我有三个互斥量: full
缓冲区满时锁定。 empty
缓冲区为空时锁定。 th
在其他人修改缓冲区时锁定。我的单个 IO 程序看起来像
operator<<(...){
full.lock() // locks when trying to push to full buffer
full.unlock() // either it's locked or not, unlock it
th.lock()
...
empty.unlock() // it won't be empty
if(...)full.lock() // it might be full
th.unlock()
operator>>(...){
// symmetric
}
这对单个 IO 完全有效。但是对于多个IO,当消费者线程解锁full
时,所有提供者线程都会关闭,只有一个会获得th
并且缓冲区可能会因为那个单线程而再次满,而不再进行完全检查。我当然可以再添加一个 full.lock()
,但这是无止境的。有没有办法同时锁定 full
和 th
?我确实看到过类似的问题,但我看不出顺序是这里的问题。
不,您不能同时锁定两个互斥量,但您可以对等待线程使用 std::condition_variable
并在完成后调用 notify_one
。
有关详细信息,请参阅 here。
是的,使用std::lock(full , th);
,这可以避免一些死锁
例如:
线程 1:
full.lock();
th.lock();
线程 2:
th.lock();
full.lock();
这可能会导致死锁,但以下情况不会:
线程 1:
std::lock(full, th);
线程 2:
std::lock(th, full);
不,您不能自动锁定两个互斥量。
此外,您似乎在一个线程中锁定了一个互斥量,然后在另一个线程中将其解锁。这是不允许的。
我建议针对此问题切换到条件变量。请注意,将一个互斥体与多个条件变量相关联是完全没问题的。
您尝试实现的功能需要类似于 System V 信号量的东西,其中可以原子地应用信号量上的一组操作。在您的情况下,您将有 3 个信号量:
- 信号量 1 - 锁定,初始化为 0
- 信号量 2 - 可用数据计数器,初始化为 0
- 信号量 3 - 可用缓冲区计数器,已初始化您有多少缓冲区
然后push操作会做这组锁:
- 检查信号量 1 是否为 0
- 将信号量 1 增加 +1
- 将信号量 2 增加 +1
- 将信号量 3 减少 -1
然后
- 将信号量 1 减少 -1
解锁。然后拉取数据第一组将更改为:
- 检查信号量 1 是否为 0
- 将信号量 1 增加 +1
- 将信号量 2 减少 -1
- 将信号量 3 增加 +1
解锁和以前一样。使用互斥体,这是特殊情况下的信号量,很可能不会以这种方式解决您的问题。首先,它们是二进制的,即只有 2 个状态,但更重要的是 API 不提供对它们的组操作。因此,您要么为您的平台找到信号量实现,要么使用带有条件变量的单个互斥量来通知等待线程数据或缓冲区可用。
我正在尝试实现多输入多输出线程间通道 class。我有三个互斥量: full
缓冲区满时锁定。 empty
缓冲区为空时锁定。 th
在其他人修改缓冲区时锁定。我的单个 IO 程序看起来像
operator<<(...){
full.lock() // locks when trying to push to full buffer
full.unlock() // either it's locked or not, unlock it
th.lock()
...
empty.unlock() // it won't be empty
if(...)full.lock() // it might be full
th.unlock()
operator>>(...){
// symmetric
}
这对单个 IO 完全有效。但是对于多个IO,当消费者线程解锁full
时,所有提供者线程都会关闭,只有一个会获得th
并且缓冲区可能会因为那个单线程而再次满,而不再进行完全检查。我当然可以再添加一个 full.lock()
,但这是无止境的。有没有办法同时锁定 full
和 th
?我确实看到过类似的问题,但我看不出顺序是这里的问题。
不,您不能同时锁定两个互斥量,但您可以对等待线程使用 std::condition_variable
并在完成后调用 notify_one
。
有关详细信息,请参阅 here。
是的,使用std::lock(full , th);
,这可以避免一些死锁
例如: 线程 1:
full.lock();
th.lock();
线程 2:
th.lock();
full.lock();
这可能会导致死锁,但以下情况不会:
线程 1:
std::lock(full, th);
线程 2:
std::lock(th, full);
不,您不能自动锁定两个互斥量。
此外,您似乎在一个线程中锁定了一个互斥量,然后在另一个线程中将其解锁。这是不允许的。
我建议针对此问题切换到条件变量。请注意,将一个互斥体与多个条件变量相关联是完全没问题的。
您尝试实现的功能需要类似于 System V 信号量的东西,其中可以原子地应用信号量上的一组操作。在您的情况下,您将有 3 个信号量:
- 信号量 1 - 锁定,初始化为 0
- 信号量 2 - 可用数据计数器,初始化为 0
- 信号量 3 - 可用缓冲区计数器,已初始化您有多少缓冲区
然后push操作会做这组锁:
- 检查信号量 1 是否为 0
- 将信号量 1 增加 +1
- 将信号量 2 增加 +1
- 将信号量 3 减少 -1
然后
- 将信号量 1 减少 -1
解锁。然后拉取数据第一组将更改为:
- 检查信号量 1 是否为 0
- 将信号量 1 增加 +1
- 将信号量 2 减少 -1
- 将信号量 3 增加 +1
解锁和以前一样。使用互斥体,这是特殊情况下的信号量,很可能不会以这种方式解决您的问题。首先,它们是二进制的,即只有 2 个状态,但更重要的是 API 不提供对它们的组操作。因此,您要么为您的平台找到信号量实现,要么使用带有条件变量的单个互斥量来通知等待线程数据或缓冲区可用。