如何使用多个编写器和多个读取器实现读者编写器

时间:2018-05-31 17:31:52

标签: c linux multithreading pthreads mutex

编写以下代码以从文件到缓冲区获取整数并从缓冲区中读取它们。有两个写入器线程读取从文件到缓冲区的整数,以及两个读取器线程从缓冲区读取整数。缓冲区大小为5,文件上可能有任意数量的整数。编写器线程必须将文件中的所有整数写入缓冲区,读取器线程必须通过缓冲区读取文件中的所有整数。读者无法直接访问该文件。由于缓冲区大小为5,当写入器将数据写入缓冲区并且它已满时,我已经放置了pthread_cond_signal(&r)来通知读者它应该开始读取。但是读者不会终止打印零。我评论了读者部分和作者部分工作,但它没有打印文件的第一个整数,两个编写器线程都读取最后的整数。 (作者线程一读100,作者线程2读100。所以缓冲区包含两个100)有人可以指出我的错误吗?

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#define BUF_SIZE 5


pthread_mutex_t m;
pthread_cond_t  r;
pthread_cond_t w;
FILE *fp;

int cnt_r= 0;
int flag =0;
int value;
int buf[BUF_SIZE];
int cnt = 0;
int z = 0;



void *read(void *parm);
void *write(void *parm);

int main(int argc, char argv[])
{

    pthread_t rid[2];
    pthread_t wid[2];

    pthread_cond_init(&r,NULL);
    pthread_cond_init(&w,NULL);


    if ((fp = fopen("/home/bhagi/2/shared_data.txt", "r")) == NULL)
        fprintf(stderr, "Couldn't find the file");


    for( int i = 0; i< 2; i++)
    {
        printf("Writer %d Starts \n",i+1);
        pthread_create(&wid[i], NULL, write,i);
    }


    for(int i = 0; i < 2; i++)
    {
        printf("Reader %d Starts \n",i+1);
        pthread_create(&rid[i],NULL,read,i);
    }

    for(int i = 0; i < 2; i++)
    {
        pthread_join(rid[i],NULL);
    }


    for(int i = 0; i < 2; i++)
    {
        pthread_join(wid[i], NULL);
    }

    fclose(fp);


    return 0;
}

void *read(void *parm)
{

    int y = (int)parm;
    int cnt_r = 0;

    pthread_mutex_lock(&m);

        while (cnt == -1)
        {
            printf("Reader %d waits \n",y+1);
            pthread_cond_wait(&r, &m);
        }
        cnt++;

    printf("Reader %d Access CS\n",y+1);
     while(flag != -1)
     {
         for(int i = 0; i < 5;i++)
         {
             printf("%d ",buf[i]);
             cnt_r++;
             sleep(1);

         }
     printf("\n %d \n",cnt_r);
     }


     cnt--;
     if(cnt == 0)
        pthread_cond_signal(&w);

    if(cnt_r != 0)
    {
        pthread_cond_signal(&r);
        printf("Reader %d Signal Reader\n",y +1);
    }
     pthread_mutex_unlock(&m);



}

void *write(void *parm)
{

    int x = (int)parm;
    int cnt_w = 0;

    while(fscanf(fp,"%d",&value) == 1)
    {

        pthread_mutex_lock(&m);
        while(cnt!= 0) {
            printf("Writer %d waits \n", x + 1);
            pthread_cond_wait(&w, &m);
        }
        cnt++;

        printf("Writer %d access cs \n",x+1);
        cnt = 0;
        pthread_cond_signal(&w);


        if(z == 5)
        {
            z = 0;
            pthread_cond_signal(&r);


        }

        buf[z] = value;
        printf("buf = %d\n",buf[z]);
        ++z;
        cnt_w++;


        sleep(1);
        printf("%d\n",cnt_w);



        pthread_mutex_unlock(&m);


    }

    flag = -1;

}

1 个答案:

答案 0 :(得分:0)

由于缓冲区大小为5,当编写器将数据写入缓冲区并且它已满时我已经放置了pthread_cond_signal(&r)

这有些倒退。一般的多个读写器模式是:

  • 作者等待缓冲区已满,然后尽可能多地写入,然后向读者发出信号;
  • 读者等待缓冲区为空,然后尽可能多地读取,然后向作者发出信号。

您需要对此进行补充,以便读者知道何时退出:

  • 作者等待缓冲区已满,然后尽可能多地写入,然后向读者发出信号。如果作者到达EOF,它会设置一个文件结束标志并发出所有读者的信号;
  • 读取器等待缓冲区为空或设置了文件结束标志。在缓冲区不为空的情况下,然后它们尽可能多地读取,然后向写入器发出信号;如果设置了文件结束标志,则退出。

就您当前代码中的具体问题而言,有两个突出的问题是:

    编写器在没有保持互斥锁的情况下访问
  • flag(这可能是读者无限循环的原因,因为编译器可以假设flag在读者持有时永远不会改变互斥);
  • value应该是编写器中的局部变量,但它是共享的(并且是非同步的) - 这可能是您的编写者从文件中看到相同编号的原因。