欢迎大家来到IT世界,在知识的湖畔探索吧!

欢迎大家来到IT世界,在知识的湖畔探索吧!
–1 条件变量的目的:
条件变量(std::condition_variable)是 C++ 中用于线程间同步的一种机制。它的主要目的是允许一个线程等待某个条件成立,而另一个线程在条件成立时通知等待的线程。条件变量通常与互斥锁(std::mutex)一起使用,以确保线程安全地访问共享资源。
–2 可不可以不带条件?
条件变量的核心是“条件”,即某个共享资源的状态。如果不带条件,那么条件变量就失去了其存在的意义。没有条件的情况下,线程间的同步将无法实现,因为线程无法知道何时应该等待或何时应该继续执行。
–3 为什么需要锁?
条件变量通常与互斥锁一起使用,因为条件变量所等待的条件通常是某个共享资源的状态。为了确保线程安全地访问和修改共享资源,必须使用锁来保护这些资源。
- 等待时:当一个线程等待某个条件成立时,它需要释放锁,以便其他线程可以修改共享资源。否则,如果线程在持有锁的情况下等待,其他线程将无法获取锁来修改共享资源,从而导致死锁。
- 唤醒时:当一个线程修改了共享资源并通知等待的线程时,它需要持有锁,以确保在通知时共享资源的状态是稳定的。
通俗点理解,可以认为有两个线程,一个生产者一个消费者,这里的条件就是“东西是否生成好了”,消费者判断好了,则消费,没好则进入等待,生产者不需要判断,生产好了就调用一次唤醒。
–4 为什么 cv.wait()需要传入锁?
cv.wait() 需要传入一个锁(通常是 std::unique_lock<std::mutex>),原因如下:
进入wait之后,内部的伪代码如下,解锁 — 阻塞等待 — 释放锁,这里的解锁就是为了让别的线程可以进入唤醒的程序:
- 避免死锁:cv.wait() 在等待时会自动释放传入的锁,允许其他线程获取锁并修改共享资源。如果没有传入锁,等待线程将一直持有锁,导致其他线程无法获取锁,从而无法修改共享资源或通知等待的线程,最终导致死锁。
- 唤醒时重新获取锁:当条件变量被通知时,cv.wait() 会自动重新获取锁,确保线程在继续执行时能够安全地访问共享资源。
–5 为什么需要传入条件?
传入条件的原因是为了避免虚假唤醒。虚假唤醒是指线程在没有收到通知的情况下从等待状态中唤醒,这可能来自于系统底层调度,C++ 默认是允许这种情况出现的。为了避免这种情况,通常会在 cv.wait() 中传入一个条件(通常是一个 lambda 表达式),线程在唤醒后会检查条件是否成立。如果条件不成立,线程会继续等待。
cv.wait(lock, []{ return shared_resource_ready; });
欢迎大家来到IT世界,在知识的湖畔探索吧!
传入条件后的伪代码如下,当出现虚假唤醒的时候,会重新进入等待:
–6 丢失唤醒怎么办?
在使用条件变量时,可能会遇到丢失唤醒(Lost Wake-up)的问题。丢失唤醒指的是在某个线程调用 cv.notify_one() 或 cv.notify_all() 时,等待的线程还没有进入 cv.wait() 状态,导致通知被“丢失”,等待的线程可能会一直阻塞。
(1) 进入wait之前需要判断wait是否有必要,比如已经有足够的数据等待消费了,就不应该进入等待
(2) 如果唤醒是循环调用的,其实是没有影响的,因为唤醒是幂等的,这次错过了,下次唤醒也可以
–7 总结:
–1 条件变量是作用于线程间同步的
–2 条件往往是某个共享资源,因此需要锁
–3 cv.wait 并不会持有锁,阻塞期间会释放锁,让notify线程可以操作共享资源
–4 注意虚假唤醒和丢失唤醒的情况
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/106059.html