1)不必要的唤醒:
1.内核:收到第一个连接请求。线程 A 和 线程 B 两个线程都在 epoll_wait() 上等待。
由于采用边缘触发模式,所以只有一个线程会收到通知。这里假定线程 A 收到通知
2.线程A:epoll_wait() 返回
3.线程A:调用 accpet() 并且成功
4.内核:此时 accept queue 为空,所以将边缘触发的 socket 的状态从可读置成不可读
5.内核:收到第二个建连请求
6.内核:此时,由于线程 A 还在执行 accept() 处理,只剩下线程 B 在等待 epoll_wait(),
于是唤醒线程 B。
7.线程A:继续执行 accept() 直到返回 EAGAIN
8.线程B:执行 accept(),并返回 EAGAIN,此时线程 B 可能有点困惑(“明明通知我有事件,结果却返回 EAGAIN”)
9.线程A:再次执行 accept(),这次终于返回 EAGAIN
2)饥饿:
1.内核:接收到两个建连请求。线程 A 和 线程 B 两个线程都在等在 epoll_wait()。
由于采用边缘触发模式,只有一个线程会被唤醒,我们这里假定线程 A 先被唤醒
2.线程A:epoll_wait() 返回
3.线程A:调用 accpet() 并且成功
4.内核:收到第三个建连请求。由于线程 A 还没有处理完(没有返回 EAGAIN),
当前 socket 还处于可读的状态,由于是边缘触发模式,所有不会产生新的事件
5.线程A:继续执行 accept() 希望返回 EAGAIN 再进入 epoll_wait() 等待,
然而它又 accept() 成功并处理了一个新连接
6.内核:又收到了第四个建连请求
7.线程A:又继续执行 accept(),结果又返回成功