Chinaunix首页 | 论坛 | 博客
  • 博客访问: 16529
  • 博文数量: 9
  • 博客积分: 370
  • 博客等级: 一等列兵
  • 技术积分: 85
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-10 00:42
文章分类
文章存档

2011年(1)

2010年(5)

2008年(3)

我的朋友
最近访客

分类: C/C++

2008-12-12 10:52:28

今天在论坛里讨论了这样一个问题:
下面的一个程序
线程共享数据初始值是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) |
给主人留下些什么吧!~~