std::timed_mutex::try_lock_for 立即失败

std::timed_mutex::try_lock_for fails immediately

本文关键字:失败 for try timed mutex std lock      更新时间:2023-10-16

我是第一次使用std::timed_mutex,它的行为方式不符合我的预期。它似乎立即失败,而不是等待互斥锁。我以毫秒为单位提供锁定超时(如图 http://www.cplusplus.com/reference/mutex/timed_mutex/try_lock_for/所示(。但是,对try_lock_for()的调用立即失败了。

下面是处理锁定和解锁互斥锁的类:

  const unsigned int DEFAULT_MUTEX_WAIT_TIME_MS = 5 * 60 * 1000;
  class ScopedTimedMutexLock
  {
  public:
     ScopedTimedMutexLock(std::timed_mutex* sourceMutex, unsigned int numWaitMilliseconds=DEFAULT_MUTEX_WAIT_TIME_MS)
        m_mutex(sourceMutex)
     {
        if( !m_mutex->try_lock_for( std::chrono::milliseconds(numWaitMilliseconds) ) )
        {
           std::string message = "Timeout attempting to acquire mutex lock for ";
           message += Conversion::toString(numWaitMilliseconds);
           message += "ms";
           throw MutexException(message);
        }
     }
     ~ScopedTimedMutexLock()
     {
        m_mutex->unlock();
     }
  private:
     std::timed_mutex* m_mutex;
  };

这就是它的使用方式:

  void  CommandService::Process( RequestType& request )
  {
     unsigned long callTime =
        std::chrono::duration_cast< std::chrono::milliseconds >(
           std::chrono::system_clock::now().time_since_epoch()
        ).count();
     try
     {
        ScopedTimedMutexLock lock( m_classMutex, request.getLockWaitTimeMs(DEFAULT_MUTEX_WAIT_TIME_MS) );
        // ... command processing code goes here
     }
     catch( MutexException& mutexException )
     {
        unsigned long catchTime =
           std::chrono::duration_cast< std::chrono::milliseconds >(
              std::chrono::system_clock::now().time_since_epoch()
           ).count();
        cout << "The following error occured while attempting to process command"
             << "n   call  time: " << callTime
             << "n   catch time: " << catchTime;
        cout << mutexException.description();
     }
  }

下面是控制台输出:

The following error occured while attempting to process command
   call  time: 1131268914
   catch time: 1131268914
Timeout attempting to acquire mutex lock for 300000ms

知道这是哪里出了问题吗?转换为std::chrono::milliseconds是否正确?如何让try_lock_for()等待锁?

附加信息:try_lock_for()的调用并不总是立即失败。很多时候,呼叫获得了锁,一切都按预期工作。我看到的失败是间歇性的。请参阅下面的回答,了解有关失败原因的详细信息。

问题的根本原因在 http://en.cppreference.com/w/cpp/thread/timed_mutex/try_lock_for 的try_lock_for()描述中提到。在描述的末尾,它说:

与 try_lock(( 一样,此函数允许虚假失败,并且 返回 false,即使互斥锁未被任何其他线程锁定 timeout_duration中的某个时间点。

我天真地认为只有两种可能的结果:(1( 函数在时间段内获取锁,或 (2( 函数在等待时间过后失败。但还有另一种可能性,(3(函数在相对较短的时间内失败,原因不明。博士,我的坏。

我通过重写 ScopedTimedMutexLock 构造函数来循环try_lock()直到获取锁或超过等待时间限制来解决此问题。

 ScopedTimedMutexLock(std::timed_mutex* sourceMutex, unsigned int numWaitMilliseconds=DEFAULT_MUTEX_WAIT_TIME_MS)
    m_mutex(sourceMutex)
 {
    const unsigned SLEEP_TIME_MS = 5;
    bool isLocked = false;
    unsigned long startMS = now();
    while( now() - startMS < numWaitMilliseconds && !isLocked )
    {
       isLocked = m_sourceMutex->try_lock();
       if( !isLocked )
       {
          std::this_thread::sleep_for(
              std::chrono::milliseconds(SLEEP_TIME_MS));
       }
    }
    if( !isLocked )
    {
       std::string message = "Timeout attempting to acquire mutex lock for ";
       message += Conversion::toString(numWaitMilliseconds);
       message += "ms";
       throw MutexException(message);
    }
 }

其中now()定义如下:

  private:
     unsigned long now() {
        return std::chrono::duration_cast< std::chrono::milliseconds >(
            std::chrono::system_clock::now().time_since_epoch() ).count();
     }

对于那些迟到的人来说,这只是一个小小的提升。非常感谢您的帮助!

具有完全相同的行为(仅在 std::shared_timed_mutex 中(。经过一番挖掘发现,如果同一线程已经对互斥锁具有独占锁,则try_lock_for()try_lock_until()都会立即失败,基本上节省了测试损坏代码的时间。

使用 gcc-9、gcc-10、clang-10 和 clang-12 进行测试。

没有测试其他可能的组合,例如请求共享锁上的独占锁或任何独占/共享锁上的共享锁。