-
#include <pthread.h>
-
-
struct msg {
-
struct msg *m_next;
-
/* ... more stuff here ... */
-
};
-
-
struct msg *workq;
-
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
-
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;
-
-
void
-
process_msg(void)
-
{
-
struct msg *mp;
-
-
for (;;) {
-
pthread_mutex_lock(&qlock);
-
while (workq == NULL)
-
pthread_cond_wait(&qready, &qlock);
-
mp = workq;
-
workq = mp->m_next;
-
pthread_mutex_unlock(&qlock);
-
/* now process the message mp */
-
}
-
}
-
-
void
-
enqueue_msg(struct msg *mp)
-
{
-
pthread_mutex_lock(&qlock);
-
mp->m_next = workq;
-
workq = mp;
-
pthread_mutex_unlock(&qlock);
-
pthread_cond_signal(&qready);
-
}
书上的示例代码如下,我的问题是,为什么不能将19行的while 改为 if (之前在我自己的代码里我用的就是if)
书上示例的下面有一段解说的文字。但是,对于我的疑问却解释的不是很清楚。最后自己想了很长时间终于想通了。
情况是这样的:
process_msg这个方法,可能被一个进程中的多个线程同时调用,换句话说,就是进程中有多个线程同时用于消息处理。
如果将代码中的while改为if,那么在以下这种情况下就会出错。
系统连续两次调用了 enqueue_msg,此时队列里面添加了两个消息和收到两次 pthread_cond_signal通知。
收到第一个pthread_cond_signal通知时,某个代码停在20行的线程被唤醒。此时可能由于该线程处理的太快,这
一个线程连续两次执行消息处理。上下文再次切换。以下分别对 while 和 if 作分析:
A. 19行是一个while,情况如下:
收到第二个pthread_cond_signal通知。某个代码停在20行的线程被唤醒继续往下运行。由于此时的代码是 while(workq == NULL) pthread_cond_wait(&qready, &qlock)。唤醒的线程会执行 workq == NULL 判断。发现 workq为空,继续等待。
B. 19行是一个if,情况如下:
收到第二个pthread_cond_signal通知。某个代码停在20行的线程被唤醒继续往下运行。由于此时的代码是 if(workq == NULL) pthread_cond_wait(&qready, &qlock) 。唤醒的线程继续往下走,而不会再次判断 workq的情况。而此时 workq 却等于 NULL,BUG就此产生了。
这种BUG非常难查找,它只会在系统长期间运行而且很繁忙的时候出现。一旦出现将会是致命性的。
读书还是要踏踏实实,书里的经验,都是前人血的教训总结出来的。
阅读(300) | 评论(0) | 转发(0) |