【问题标题】:Strange C++11 mutex behavior奇怪的 C++11 互斥行为
【发布时间】:2026-01-03 08:10:01
【问题描述】:

我正在尝试使用二进制信号量来实现计数信号量。

代码逻辑是众所周知的,并且在使用 Qt 的QMutex 类之前已经过测试,并且可以正常工作(使用生产者-消费者多线程驱动程序进行测试)。 我已经尝试手动控制l mutex(锁定类)、lock_guardunique_lock 对象,但没有效果。

调用acquire() 的线程似乎在block 互斥锁上被阻塞(尽管并非始终如此),即使其他线程调用block.unlock() 也是如此。使代码工作的唯一方法是将block.lock() 行替换为while(block.try_lock()); 然后一切正常。

如果我将 block 互斥体替换为条件变量,则代码有效。

#include <mutex>

class semaphore
{
private:
    int value=0;
    std::mutex l, block;

public:
    semaphore(int i=0);
    semaphore(const semaphore&)=delete;
    semaphore(const semaphore&&)=delete;
    semaphore & operator=(const semaphore&)=delete;
    semaphore & operator=(const semaphore&&)=delete;
    void acquire();
    void acquire(unsigned int i);
    void release(unsigned int i=1);
    int available();
    bool try_acquire(unsigned int i=1);
};

//---------------------------------
semaphore::semaphore(int i)
{
    value=i;
    block.lock(); // make sure that any thread trying to lock will block
}
//---------------------------------
void semaphore::acquire()
{
    l.lock();
    value--;  

    if(value <0)
     {
        l.unlock();  // release the semaphore while waiting
        while( block.try_lock());  // LINES IN QUESTION 
        //block.lock();            // LINES IN QUESTION 
     }
     else
         l.unlock();
}
//---------------------------------
void semaphore::acquire(unsigned int i)
{ 
    while(i--)
        this->acquire();
}
//---------------------------------
void semaphore::release(unsigned int i)
{
  l.lock();
  while(i--)
    {
      value++;  
      if(value <=0)
        block.unlock();
    }
  l.unlock();  
}
//---------------------------------
int semaphore::available()
{
    std::unique_lock<std::mutex> guard(l);
    return value;
}
//---------------------------------
bool semaphore::try_acquire(unsigned int i)
{
    l.lock();
    bool res=false;
    if(value>=(int)i)
    {
        value-=i;
        res=true;
    }
    l.unlock();
    return res;
}

【问题讨论】:

  • 永远不要手动拨打lockunlock。而是使用std::lock_guard and friends,否则如果您出于某种原因提前离开范围,您将面临死锁的风险。
  • 注意:mutex 不是二进制信号量。如果你有一个二进制信号量(或计数信号量),那么你可以像互斥体一样使用它,但反之则不然。可以以互斥锁不能使用的方式使用二进制信号量。 StaceyGirl 的回答(如下)描述了一些你可以用二进制信号量做的事情,而你不能用互斥锁做。
  • 谢谢大家。非常感谢。

标签: c++ multithreading c++11 mutex


【解决方案1】:

未定义的行为:

  • try_lock 不能由已经拥有互斥锁的线程调用,否则,行为未定义。 while( block.try_lock()); 行不正确。
  • unlock 只能由拥有互斥锁的线程调用,否则行为未定义。

QtMutex 的#2 也是错误的。如果代码“工作”了,那是偶然的。

您需要一个适当的信号量实现,它已被部分覆盖here

【讨论】:

    最近更新 更多