交换互斥锁
Swapping mutex locks
我在正确"交换"锁时遇到问题。请考虑以下情况:
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
上。
我想让最后 2 个线程等待this->waitMutex
可用。
编辑 2:
带有osBlockingFunction
的扩展示例。
它闻起来好像设计/实现应该有点不同,HidDevice::wait
上的std::condition_variable cv
并且只有一个互斥锁。当你写"其他线程可以执行其他方法或中止这个"时,会调用cv.notify_one
来"中止"这个等待。cv.wait
{enter 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();
}
}
类似的东西。
我建议创建一个小的"解锁"工具。 这是一个具有反转语义的互斥包装器。lock
它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
而不是持有mutex
的lock_guard
。
这将锁定waitLock
并解锁mutex
,就像通过一条不间断的指令一样。
现在,在编写了所有这些代码之后,我可以推断它可以转换为:
waitLock.lock();
lock.unlock(); // lock must be a unique_lock to do this
第一个版本是否具有或多或少的可读性是一个意见问题。 第一个版本更容易推理(一旦知道std::lock
做什么)。 但第二个更简单。 但对于第二个,读者必须更仔细地思考正确性。
更新
只需阅读问题中的编辑。 此解决方案无法解决编辑中的问题:第二个线程将阻止第三个(和后续线程)在任何需要mutex
但不waitMutex
的代码中取得进展,直到第一个线程释放waitMutex
。
所以从这个意义上说,我的答案在技术上是正确的,但不能满足所需的性能特征。 我将把它留给参考。
- C++嵌套if语句,基本货币交换
- shell排序中的交换和比较
- 排序时无法执行交换操作.我做的时候它会崩溃.为什么
- 通过交换元素使数组相同
- 如何使 std::sort 在 std::swap 和我的命名空间的模板化交换之间没有名称冲突?
- 交换运算符 + 重载会导致无限递归
- 为什么 std::reduce 需要交换性?
- 复制和交换习惯用法与移动操作之间的交互
- C++ - 没有自定义交换功能的移动分配运算符?
- 如何在数组中交换最小和最大的位置?
- 尽管一切看起来都很好,但值不会交换
- C++交换来自同一类成员的参数值,处理多个类
- 插入排序的最小交换
- C++在 2 个向量向量之间交换向量
- 转置矩阵:交换元素不会更改值
- 不正确的比较和交换计数器输出用于快速排序功能
- 交换函数不是在 C++ 中交换 2D 数组的元素
- std::vector move 而不是交换到空 vector 并释放存储
- 否,除了交换和移动具有互斥锁的类
- 如何交换数组中的元素?