繁体   English   中英

我是否有风险在 C++ 中使用 std::condition_variable 使线程陷入死锁?

[英]Do I have a risk to put a thread in deadlock with std::condition_variable in C++?

这是一个更理论的问题。 我已经看到了几个带有std::condition_variable的例子,它似乎让线程进入睡眠状态,直到满足条件。 这是种族上的某种旗帜,是有道理的。

但似乎如果一个变量总是改变,那么一个线程可能会被唤醒以检查条件并再次入睡,因为当谓词为真时它没有跟上捕捉情况,所以我可能会将线程置于“昏迷”状态.

那么,当我总是在这种情况下使用它时, std::condition_variable是否不安全?

这就是为什么在使用条件变量时也必须使用互斥锁的原因。 我认为您错过了线程开始等待并同时锁定互斥锁的事实。 更改条件的线程也必须在更改条件时锁定互斥锁。

线程 1:

Lock mutex
Check condition (it's false)
Unlock mutex and start waiting (these happen at the exact same time)
Finish waiting and lock mutex
Check condition (it's true)
Unlock mutex

线程 2:

Lock mutex
Change condition
Unlock mutex
Notify condition variable

当条件已经为真时,线程 1 不可能等待。 因为当互斥锁被锁定时条件不能改变,并且互斥锁直到线程 1 已经在等待时才会解锁。

有可能在线程 2 释放互斥体之后,但在线程 2 通知它之前,线程 1 可能会虚假唤醒,看到条件为真,做一些其他的事情,然后再次开始等待。 然后线程 2 将通知条件变量,线程 1 将其视为虚假唤醒。

您似乎在谈论某种“活锁”。 死锁是一个或多个线程在等待释放锁时没有进展的情况。 Livelock 类似,但过程的 state 不断变化,但仍然没有进展。 我们还可以谈论“实际上是活锁的”,即线程没有足够的机会取得足够的进展。

对于观察者来说,活锁和实际活锁通常看起来很像真正的死锁。

您应该设计程序逻辑以避免活锁。 它可以是不平凡的。 例如,许多 forms 的锁并不“公平”。 也就是说,当许多线程正在等待一个被释放的锁时,首先请求它的锁并不能保证接下来会收到它。

事实上,许多操作系统锁本质上是不公平的,例如,将锁分配给更容易唤醒(例如加载到内核并挂起)而不是更难(从内核卸载并需要重新加载以恢复执行)的线程。

这个问题没有提供很多细节,因此很难诊断这种情况。 如果某些特定线程(或线程的 class)需要优先级,您可以引入一个标志,告诉低优先级线程在优先级线程正在等待(并且可以运行)时不获取锁,例如(c && !(p && priority_waiting))其中c是低优先级线程的逻辑条件, p是优先级线程的逻辑条件。

您当然应该避免线程等待潜在瞬态条件的逻辑。 假设您有一些监视器线程,每 1000 个周期产生 output。 (cycles%1000 == 0)这样的等待条件很容易错过点击计数器。 他们应该更有可能像(cycles-lcycles >=0)一样,其中lcycles是监视器上次恢复处理时的周期数。 这确保了监视器通常会获得一个它可能(出于实际目的)几乎永远不会捕获的锁。

在该示例中,线程正在等待(a)获取锁的机会和(b)一些瞬态条件。 有一种风险是两者都很少同时发生,并且线程可能被活锁或实际上被活锁并且进展不足,

简而言之,确保线程在条件通过时恢复,而不是在条件完全满足时恢复。

你可以引入一个严格的队列来给线程轮流。 除非文档明确承诺公平,否则不要假设这是您所拥有的。

这就是为什么condition_variable总是与锁( mutex )结合使用的原因。

生产者和消费者逻辑都是在持有相同锁的情况下执行的,因此任何共享数据(例如队列、某些条件标志等)一次只能由一个线程访问。

在释放锁时通知condition_variable变量,等待线程在唤醒时获取锁。 所以实际上,锁从生产者转移到消费者线程,并且在消费者有机会看到它之前设置条件和取消设置它是不可能的,如果至少有一个其他线程已经在等待它。

换句话说, condition_variable::notify_one保证至少唤醒一个等待线程( condition_variable::wait ),如果有的话。 当然,生产者应该在调用notify_one之前或之后释放锁,以便让等待的线程继续进行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM