如何解决与局部互斥量一起使用条件变量
在查看大型项目的遗留代码时,我发现使用了一些奇怪的方法来创建线程安全队列,如下所示:
template < typename _Msg>
class WaitQue: public QWaitCondition
{
public:
typedef _Msg DataType;
void wakeOne(const DataType& msg)
{
QMutexLocker lock_(&mx);
que.push(msg);
QWaitCondition::wakeOne();
}
void wait(DataType& msg)
{
/// wait if empty.
{
QMutex wx; // WHAT?
QMutexLocker cvlock_(&wx);
if (que.empty())
QWaitCondition::wait(&wx);
}
{
QMutexLocker _wlock(&mx);
msg = que.front();
que.pop();
}
}
unsigned long size() {
QMutexLocker lock_(&mx);
return que.size();
}
private:
std::queue<DataType> que;
QMutex mx;
};
在线程中使用 wakeOne
作为“发布功能”,从其他线程中调用wait
并无限期地等待直到消息出现在队列中。阶段并使用单独的队列。
通过创建本地QMutex
来使用que
的这种合法方法吗?我有点理解为什么有人在读取import cv2
img = cv2.imread(os.path.join(path,file))
image_face = DeepFace.detectFace(img)
的大小时可以这样做来避免死锁,但是它甚至如何工作?有没有更简单,更惯用的方式来实现此行为?
解决方法
具有局部条件变量是合法的。但这通常没有任何意义。
在这种情况下,您所做的工作是错误的。您应该使用成员:
void wait(DataType& msg)
{
QMutexLocker cvlock_(&mx);
while (que.empty())
QWaitCondition::wait(&mx);
msg = que.front();
que.pop();
}
还请注意,对while
的呼叫周围必须有if
而不是QWaitCondition::wait
。这是由于(可能)虚假唤醒引起的复杂原因-Qt文档在此处不清楚。但更重要的是,互斥锁的唤醒和随后的重新获取不是原子操作,这意味着您必须重新检查变量队列是否为空。可能是最后一种情况,您之前遇到了死锁/ UB。
考虑一个空队列和一个将wait
插入QWaitCondition::wait
的调用方(线程1)的情况。该线程阻塞。然后线程2出现并将一个项目添加到队列并调用wakeOne
。线程1被唤醒,并尝试重新获取互斥量。但是,线程3会在您的wait实现中出现,在线程1之前使用互斥锁,看到队列不为空,处理单个项目并继续前进,释放互斥锁。然后被唤醒的线程1最终获取了互斥锁,从QWaitCondition::wait
返回并尝试处理...一个空队列。 kes。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。