我们程序中常常会使用到线程间的消息同步处理,比如以下一段伪码
var message = ""; void func() { 1. 启动线程Thread(该线程中填充message的内容); 2. 阻塞,直到等待到完成message填充的事件; 3. 处理message; .... } void Thread() { 1. 通过某种处理填充message; 2. 触发func中的阻塞事件; }
我们通常会使用条件变量来完成类似情况的线程同步处理
-
比如windows平台下CreateEvent,WaitForSingleObject,SetEvent...;
-
Linux平台下的pthread_cond_init,pthread_cond_wait,pthread_cond_signal...。
看上去很完美的模型。但是在Linux平台下使用条件变量来完成这种需求是有风险的,要知道操作系统对线程的调度是我们不可控的。设想这样一种情况:func中步骤1的线程有可能已经触发了阻塞事件,但是func步骤2还未执行。这时这个事件如果在Linux平台下使用条件变量就会丢失通知。这样对于步骤2就面临着永远阻塞或者超时这些我们不期望的逻辑。(这种情况在我写的客户端网络SDK的linux版本下遇过的,我发出去一条带有标识的消息,然后利用条件变量阻塞10秒等待这个标识消息,但是时常会遇见等待超时的情况,按说是不可能超时的,最后经过详细调查才发现是由于pthread库的条件变量触发机制导致的。)但是在windows下使用Event却不会出现这种情况。
举个简单的例子:
-
linux下pthread库的条件变量触发机制好比:你和女神妹子约好在某个地方见面,理应你先到的,结果因为你堵车妹子先到了,一看你没来,生气走了。约会泡汤,哭去吧你。
-
windows下的事件的触发机制好比:你和屌丝妹子约好在某个地方见面,理应你先到,但你故意晚来想气走妹子,结果妹子先到却一直等你。约会进行中,哭去吧你。
那么我们有没有办法在linux平台下实现一种更可靠的消息同步机制,屌丝福音:使用posix信号量sem_init,sem_t imedwait,sem_post...。另外使用select和epoll的水平触发也可以变向实现这种情况下的消息同步(监控管道一端的读,一端写来触发消息)。
推荐阅读:《Linux 的多线程编程的高效开发经验》