[英]std::timed_mutex::try_lock_for fails immediately
I'm using a std::timed_mutex
for the first time and it's not behaving the way I expect.我第一次使用
std::timed_mutex
,它的行为方式与我预期的不同。 It appears to fail immediately instead of waiting for the mutex.它似乎立即失败,而不是等待互斥锁。 I'm providing the lock timeout in milliseconds (as shown here http://www.cplusplus.com/reference/mutex/timed_mutex/try_lock_for/ ).
我以毫秒为单位提供锁定超时(如此处所示http://www.cplusplus.com/reference/mutex/timed_mutex/try_lock_for/ )。 But the call to
try_lock_for()
fails right away.但是对
try_lock_for()
的调用立即失败。
Here's the class that handles locking and unlocking the mutex:这是处理锁定和解锁互斥量的 class:
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;
};
And this is where it's being used:这就是它被使用的地方:
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();
}
}
Here's the console output:这是控制台 output:
The following error occured while attempting to process command
call time: 1131268914
catch time: 1131268914
Timeout attempting to acquire mutex lock for 300000ms
Any idea where this is going wrong?知道哪里出了问题吗? Is the conversion to
std::chrono::milliseconds
correct?转换为
std::chrono::milliseconds
是否正确? How do I make try_lock_for()
wait for the lock?如何让
try_lock_for()
等待锁?
ADDITIONAL INFO: The call to try_lock_for()
didn't always fail immediately.附加信息:对
try_lock_for()
的调用并不总是立即失败。 Many times the call acquired the lock and everything worked as expected.多次调用获得了锁,一切都按预期进行。 The failures I was seeing were intermittent.
我看到的失败是断断续续的。 See my answer below for details about why this was failing.
有关失败原因的详细信息,请参阅下面的答案。
Just a little bump-up for those who come late.只是给迟到的人一点点奖励。 And many thanks for help!
非常感谢您的帮助!
Got quite same behavior (only in std::shared_timed_mutex).得到完全相同的行为(仅在 std::shared_timed_mutex 中)。 After some digging found out that both
try_lock_for()
and try_lock_until()
fail immediately if same thread already has exclusive lock on mutex, basically saving time on testing broken code.经过一番挖掘后发现,如果同一个线程已经对互斥锁进行了独占锁定,那么
try_lock_for()
和try_lock_until()
都会立即失败,基本上可以节省测试损坏代码的时间。
Tested with gcc-9, gcc-10, clang-10 and clang-12.已使用 gcc-9、gcc-10、clang-10 和 clang-12 进行测试。
Did NOT tested other possible combinations like requesting exclusive lock over shared lock or requesting shared lock over any of exclusive/shared locks.没有测试其他可能的组合,例如请求排他锁而不是共享锁或请求共享锁而不是任何排他/共享锁。
The root cause of the problem is mentioned in the description for try_lock_for()
at http://en.cppreference.com/w/cpp/thread/timed_mutex/try_lock_for . 在http://en.cppreference.com/w/cpp/thread/timed_mutex/try_lock_for的
try_lock_for()
描述中提到了问题的根本原因。 Near the end of the description it says: 在说明的末尾说:
As with try_lock(), this function is allowed to fail spuriously and return false even if the mutex was not locked by any other thread at some point during timeout_duration.
与try_lock()一样,即使在timeout_duration期间的某个时间点,互斥锁没有被任何其他线程锁定,也允许该函数错误地失败并返回false。
I naively assumed there were only two possible outcomes: (1) the function acquires the lock within the time period, or (2) the function fails after the wait time has elapsed. 我天真地假设只有两种可能的结果:(1)该函数在该时间段内获取了锁定,或者(2)该函数在等待时间过去之后失败了。 But there is another possibility, (3) the function fails after a relatively short time for no specified reason.
但是还有另一种可能性,(3)该功能在较短时间内无缘无故失败。 TL;DR, my bad.
TL; DR,我不好。
I solved the problem by rewriting the ScopedTimedMutexLock
constructor to loop on try_lock()
until the lock is acquired or the wait time limit is exceeded. 我通过重写
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);
}
}
Where now()
is defined like this: now()
的定义如下:
private:
unsigned long now() {
return std::chrono::duration_cast< std::chrono::milliseconds >(
std::chrono::system_clock::now().time_since_epoch() ).count();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.