同时锁定两个互斥对象

Lock two mutex at same time

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

我正在尝试实现一个多入多出的线程间通道类。我有三个互斥对象:当缓冲区已满时,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(),但这是无穷无尽的。有没有办法同时锁定fullth?我确实看到了类似的问题,但我不认为秩序是问题所在。

是的,使用std::lock(full , th);,这可以避免的一些死锁

例如:线程1:

full.lock();
th.lock();

线程2:

th.lock();
full.lock();

这可能会导致死锁,但以下情况不会:

线程1:

std::lock(full, th);

线程2:

std::lock(th, full);

不,不能原子锁定两个互斥对象。

此外,看起来您在一个线程中锁定互斥对象,然后在另一个线程中将其解锁。这是不允许的。

对于这个问题,我建议切换到条件变量。请注意,将一个互斥对象与多个条件变量关联起来是完全可以的。

不,您不能同时锁定两个互斥体,但您可以为等待的线程使用std::condition_variable,并在完成后调用notify_one
请参阅此处了解更多详细信息。

您试图实现的功能需要类似于System V信号量的东西,其中可以原子地应用信号量上的一组操作。在你的情况下,你会有3个信号量:

  • 信号量1-锁定,初始化为0
  • 信号量2-可用数据的计数器,初始化为0
  • 信号量3-可用缓冲区的计数器,初始化您有多少缓冲区

则推送操作将执行此组锁定:

  • 检查信号量1为0
  • 将信号量1增加+1
  • 将信号量2增加+1
  • 将信号量3减少-1

然后

  • 将信号量1减少-1

解锁。则要提取数据,第一组将更改为:

  • 检查信号量1为0
  • 将信号量1增加+1
  • 将信号量2减少-1
  • 将信号量3增加+1

解锁与以前相同。使用互斥锁,这是一种特殊情况下的信号量,很可能不会以这种方式解决您的问题。首先,它们是二进制的,即只有2个状态,但更重要的是API不提供对它们的组操作。因此,您可以为您的平台找到信号量实现,或者使用带有条件变量的单个互斥体来向等待的线程发出数据或缓冲区可用的信号。