我很难正确地“换”锁。考虑一下这种情况:
bool HidDevice::wait(const std::function<bool(const Info&)>& predicate)
{
/* A method scoped lock. */
std::unique_lock waitLock(this->waitMutex, std::defer_lock);
/* A scoped, general access, lock. */
{
std::lock_guard lock(this->mutex);
bool exitEarly = false;
/* do some checks... */
if (exitEarly)
return false;
/* Only one thread at a time can execute this method, however
other threads can execute other methods or abort this one. Thus,
general access mutex "this->mutex" should be unlocked (to allow threads
to call other methods) while at the same time, "this->waitMutex" should
be locked to prevent multiple executions of code below. */
waitLock.lock(); // How do I release "this->mutex" here?
}
/* do some stuff... */
/* The main problem is with this event based OS function. It can
only be called once with the data I provide, therefore I need to
have a 2 locks - one blocks multiple method calls (the usual stuff)
and "waitLock" makes sure that only one instance of "osBlockingFunction"
is ruinning at the time. Since this is a thread blocking function,
"this->mutex" must be unlocked at this point. */
bool result = osBlockingFunction(...);
/* In methods, such as "close", "this->waitMutex" and others are then used
to make sure that thread blocking methods have returned and I can safely
modify related data. */
/* do some more stuff... */
return result;
}我如何解决这个“交换”问题而不过于复杂的代码?在锁定另一个this->mutex之前,我可以先解锁,但是我担心在纳秒内,可能会出现竞争状态。
编辑:
假设有3个线程正在调用wait方法。第一个锁this->mutex,然后锁定this->waitMutex,然后解锁this->mutex。第二个锁将锁定this->mutex,必须等待this->waitMutex可用。它不会解锁this->mutex。第三个会被锁在this->mutex上。
我想让最后两个线程等待this->waitMutex可用。
编辑2:
用osBlockingFunction扩展示例。
发布于 2018-07-15 22:04:04
看起来,std::condition_variable cv在HidDevice::wait上的设计/实现应该有点不同,只有一个互斥对象。当您编写“其他线程可以执行其他方法或中止此方法”时,将调用cv.notify_one以“中止”此等待。cv.wait {输入、等待和解锁互斥},在cv.notify {退出等待并以原子方式锁定互斥锁。就像这样,HidDevice::wait更简单:
bool HidDevice::wait(const std::function<bool(const Info&)>& predicate)
{
std::unique_lock<std::mutex> lock(this->m_Mutex); // Only one mutex.
m_bEarlyExit = false;
this->cv.wait(lock, spurious wake-up check);
if (m_bEarlyExit) // A bool data-member for abort.
return;
/* do some stuff... */
}/* do some checks... */上,线程等待某些逻辑的实现。“中止”等待,将由其他线程调用的其他HidDevice函数负责:
void HidDevice::do_some_checks() /* do some checks... */
{
if ( some checks )
{
if ( other checks )
m_bEarlyExit = true;
this->cv.notify_one();
}
}类似的东西。
发布于 2018-07-15 22:12:20
我建议建立一个小小的“解锁”设施。这是一个具有反向语义的互斥包装器。在lock it unlocks和反之亦然:
template <class Lock>
class unlocker
{
Lock& locked_;
public:
unlocker(Lock& lk) : locked_{lk} {}
void lock() {locked_.unlock();}
bool try_lock() {locked_.unlock(); return true;}
void unlock() {locked_.lock();}
};现在取代:
waitLock.lock(); // How do I release "this->mutex" here?相反,你可以说:
unlocker temp{lock};
std::lock(waitLock, temp);其中lock是unique_lock而不是lock_guard holding mutex。
这将锁定waitLock和解锁mutex,就像通过一个不间断的指令。
现在,在编写所有这些代码之后,我可以推断它可以转换为:
waitLock.lock();
lock.unlock(); // lock must be a unique_lock to do this第一个版本的可读性是多的还是少的,这是一个意见问题。第一个版本更容易推理(一旦知道std::lock做了什么)。但第二个更简单。但对于第二个问题,读者必须更仔细地思考其正确性。
更新
只需阅读问题中的编辑。此解决方案没有解决编辑中的问题:第二个线程将阻止第三个线程(以及后面的线程)在任何需要mutex而不是waitMutex的代码中取得进展,直到第一个线程释放waitMutex为止。
因此,在这个意义上,我的答案在技术上是正确的,但不符合预期的性能特征。我会把它放在一边,以供参考。
https://stackoverflow.com/questions/51352436
复制相似问题