今天在论坛里讨论了这样一个问题:
下面的一个程序
线程共享数据初始值是0
mywrite线程每次把这个值加1,通知myread线程读出来写到终端,循环90000次
但是每次的执行结果是随机的,有的是300多次,有的600多次
而在linux下只输出一个1
/* * 一个线程写,一个线程读; 写一次,读一次 * */ #include <stdio.h> #include <pthread.h>
#define MAXNUM 90000
void *mywrite(void *);
void *myread(void *);
int critical_number = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t condwr = PTHREAD_COND_INITIALIZER; pthread_cond_t condrd = PTHREAD_COND_INITIALIZER;
int main() { pthread_t tid_wr, tid_rd; pthread_setconcurrency(2); pthread_create(&tid_wr, NULL, mywrite, NULL); pthread_create(&tid_rd, NULL, myread, NULL);
sleep(1); // 这个必须,否则mywrite线程还没等待,条件变量信号会丢失
pthread_cond_signal(&condwr); // 启动write线程
pthread_join(tid_wr, NULL); pthread_join(tid_rd, NULL); return 0; }
void *mywrite(void *arg) // 一直增加n,直到MAXNUM
{ for(int i=0; i<MAXNUM; i++) { pthread_mutex_lock(&mutex); pthread_cond_wait(&condwr, &mutex); critical_number ++; pthread_cond_signal(&condrd); // 通知read可以输出了
pthread_mutex_unlock(&mutex); } return NULL; }
void *myread(void *arg) { for(int i=0; i<MAXNUM; i++) { pthread_mutex_lock(&mutex); pthread_cond_wait(&condrd, &mutex); printf("%d\n", critical_number); pthread_cond_signal(&condwr); // 通知write可以修改了
pthread_mutex_unlock(&mutex); } return NULL; }
|
这个程序会出现死锁的现象,问题出在pthread_cond_wait函数,这个函数并不是原子操作,如果条件不满足,它会完成两个操作,一,释放锁。二,进入条件等待队列。所以如果写操作完成后,再次被CPU轮寻,pthread_cond_wait时发现读操作没有做,释放锁(此时恰巧读操作获得CPU并运行完成,发送条件),并进入等待队列(此时由于读操作的信号已经发送完了,所以丢失了一个信号),这时候不管读还是写获得了CPU,都无法得到条件,两个线程死锁。
正确的写法
#include <stdio.h> #include <unistd.h> #include <pthread.h>
#define MAXNUM 100 #define TRUE 1 #define FALSE 0
void *mywrite(void *);
void *myread(void *);
int critical_number = 0; int wrReady = TRUE; int rdReady = FALSE; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t condwr = PTHREAD_COND_INITIALIZER; pthread_cond_t condrd = PTHREAD_COND_INITIALIZER;
int main() { pthread_t tid_wr, tid_rd;
pthread_create(&tid_wr, NULL, mywrite, NULL); pthread_create(&tid_rd, NULL, myread, NULL);
pthread_join(tid_wr, NULL); pthread_join(tid_rd, NULL);
return 0; }
void *mywrite(void *arg) { for(int i=0; i<MAXNUM; i++) { pthread_mutex_lock(&mutex); while (!wrReady) pthread_cond_wait(&condwr, &mutex); critical_number ++; rdReady = TRUE; wrReady = FALSE; pthread_cond_signal(&condrd);
pthread_mutex_unlock(&mutex); } return NULL; }
void *myread(void *arg) { for(int i=0; i<MAXNUM; i++) { pthread_mutex_lock(&mutex); while (!rdReady) pthread_cond_wait(&condrd, &mutex); printf("%d\n", critical_number); wrReady = TRUE; rdReady = FALSE; pthread_cond_signal(&condwr);
pthread_mutex_unlock(&mutex); } return NULL; }
|
这样就解决了死锁的问题。
阅读(570) | 评论(0) | 转发(0) |