1.pthread_cond_wait的 虚假唤醒
什么是虚假唤醒?简单说就是wait这个函数返回了,但是它等的那个条件并不满足。
为什么会这样? 有两种原因
- 这个条件从来就没有满足过,wiat函数的返回不是因为别的线程调用signal或者broadcast把你唤醒,而是因为wait函数被信号中断。(虚假唤醒的一个可能性是条件变量的等待被信号中断。)
pthread 的条件变量等待
pthread_cond_wait
是使用阻塞的系统调用实现的(比如 Linux 上的futex
),这些阻塞的系统调用在进程被信号中断后,通常会中止阻塞、直接返回 EINTR 错误。同样是阻塞系统调用,你从
read
拿到 EINTR 错误后可以直接决定重试,因为这通常不影响它本身的语义。而条件变量等待则不能,因为本线程拿到 EINTR 错误和重新调用futex
等待之间,可能别的线程已经通过pthread_cond_signal
或者pthread_cond_broadcast
发过通知了。(也就是说你准备重新等待的时候,你女神发短信说答应跟你在一起了,但是你这时候把手机给扔了,继续等待,直接gg)。所以对条件的判断要放在while里面。
信号:内核给一个进程发送软中断信号的方法,是在进程所在的进程表项的信号域设置对应于该信号的位。这里要补充的是,如果信号发送给一个正在睡眠的进程,那么要看 该进程进入睡眠的优先级,如果进程睡眠在可被中断的优先级上,则唤醒进程;否则仅设置进程表中信号域相应的位,而不唤醒进程。这一点比较重要,因为进程检 查是否收到信号的时机是:一个进程在即将从内核态返回到用户态时;或者,在一个进程要进入或离开一个适当的低调度优先级睡眠状态时。
转自: https://www.cnblogs.com/sure/p/3782773.html
第二个要 引起注意的是,如果要捕捉的信号发生于进程正在一个系统调用中时,并且该进程睡眠在可中断的优先级上,这时该信号引起进程作一次longjmp,跳出睡眠 状态,返回用户态并执行信号处理例程。当从信号处理例程返回时,进程就象从系统调用返回一样,但返回了一个错误代码,指出该次系统调用曾经被中断。这要注 意的是,BSD系统中内核可以自动地重新开始系统调用。
第三个要注意的地方:若进程睡眠在可中断的优先级上,则当它收到一个要忽略的信号时,该进程被唤醒,但不做longjmp,一般是继续睡眠。但用户感觉不到进程曾经被唤醒,而是象没有发生过该信号一样。2、 这个条件曾经满足过,但是被人截胡了。由于线程调度的原因,被条件变量唤醒的线程A在本线程内真正执行「加锁并返回」前,另一个线程B也被唤醒了,并且比你更快,直接已经完整地进行了一套「拿锁、改条件、还锁」的操作。那这时候等到你拿锁的时候,条件变量实际上已经不满足了。(不管broadcast还是signal,实际都会不止唤醒一个线程,signal是为了性能的考虑,unp有关于这一点的说明)
怎么办?
其实就是把对条件的判断放在while循环里,而不能用if语句。
条件变量:https://www.ibm.com/developerworks/cn/linux/thread/posix_thread3/index.html
虚假唤醒:https://www.zhihu.com/question/271521213
条件变量使用方法:
pthread_mutex_lock(&m_mutex);
while(Work !=4){
pthread_cond_wait(&m_cond,&m_mutex);
}
//对work do something
pthread_unlock(&m_mutex);
2. 并发模型
2. reactor和proactor
其实我也不是很理解,只理解了一个区别是reactor 是同步I/O操作,Proactor是异步I/O操作
https://www.zhihu.com/question/26943938