0
votes

I would like to ask for help with this task.

My task is write an easy program in C which simulates readers-writers problem. The program requirements are:

  1. After program start, the user will be asked for enter count of writers and readers.

  2. Program will continously inform the user about status of the threads.

  3. After end of the program, little statistic (how many times had every reader read and every writer write).

I have done some basic structure of the program (dealing with the critical section through semaphores etc.), but I think that the program does not do, what it should do. Program runs without fault or unexpected behavior, but the counts, how many times had every reader read and every writer write are always one for each reader or writer).

Where am i wrong? Maybe I don't understand the task well.

Thank You very much for response.

Program code:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

sem_t w;    // write access
sem_t m;    // mutex
int rc=0;   // readers count

int writersCount;
int readersCount;
pthread_t writersThread[10], readersThread[10];
int writeCount[10], readCount[10];
int i;

void *writer(void *i) {
    int a = *((int *) i);

    sem_wait(&w);   // P(w)
    printf("Writer %d writes to DB.\n",a+1);
    writeCount[a+1]++;  
    sem_post(&w);   // V(w)

    free(i);
}

void *reader(void *i) {
    int a = *((int *) i);

    sem_wait(&m);   // P(m)
    rc++;
    if (rc == 1) {
        sem_wait(&w);   // P(w)
    }
    sem_post(&m);   // V (m)

    printf("Reader %d reads from DB.\n",a+1);
    readCount[a+1]++;   

    sem_wait(&m);   // P(m)
    rc--;
    if (rc == 0) {
        sem_post(&w);   // V(w)
    }
    sem_post(&m);   // V(m)

    free(i);
}

int main() {
    sem_init(&w,0,1);
    sem_init(&m,0,1);

    printf("Enter count of writers:");
    scanf("%d",&writersCount);
    printf("Enter count of readers:");
    scanf("%d",&readersCount);

    for (i=0; i<readersCount; i++) {
        int *arg = malloc(sizeof(*arg));
        *arg = i;
        pthread_create(&readersThread[i], NULL, reader, arg);
    }
    for (i=0; i<writersCount; i++) {
        int *arg = malloc(sizeof(*arg));
        *arg = i;
        pthread_create(&writersThread[i], NULL, writer, arg);
    }
    for (i=0; i<writersCount; i++) {
        pthread_join(writersThread[i], NULL);
    }   
    for (i=0; i<readersCount; i++) {
        pthread_join(readersThread[i], NULL);
    }

    printf("--------------\n");
    for (i=0; i<readersCount; i++) {
        printf("Reader %d read %d times\n",i+1,readCount[i+1]);
    }

    for (i=0; i<writersCount; i++) {
        printf("Writer %d wrote %d times\n",i+1,writeCount[i+1]);
    }

    sem_destroy(&w);
    sem_destroy(&m);
    return 0;
}

Output: Enter count of writers:4 Enter count of readers:4

Reader 1 reads from DB.
Reader 3 reads from DB.
Reader 4 reads from DB.
Reader 2 reads from DB.
Writer 1 writes to DB.
Writer 2 writes to DB.
Writer 3 writes to DB.
Writer 4 writes to DB.
--------------
Reader 1 read 1 times
Reader 2 read 1 times
Reader 3 read 1 times
Reader 4 read 1 times
Writer 1 wrote 1 times
Writer 2 wrote 1 times
Writer 3 wrote 1 times
Writer 4 wrote 1 times
2
You can't use global variables across threads.Iharob Al Asimi
Thank You for response. I guess, you are talking about that variables int writeCount[10] and int readCount[10], am I right? Could You please suggest me proper way to count how many times, had reader read and writer write? Thank You.Pavel Straka
Create a structure and pass it to pthread_create function, each thread it's own data.Iharob Al Asimi
@iharob it seems to me that each thread is accesing it's own element in the arrays writeCount and readCount. There is only one shared variable rc that is protected with mutex m.vasicbre
@vasicbre yes you are absolutely right.Iharob Al Asimi

2 Answers

2
votes

Your output is perfectly correct since every thread you run does exactly one read/write. Put some loops in reader/writer functions to change that fact. Your program may encounter an error when you run it with 10 readers or writers because one of them will try to access writeCount[10] or readCount[10], change that and you have a correct program.

1
votes

You can try this, but please pick vasicbre's answer because he is the one who found the problem first.

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

sem_t w;    // write access
sem_t m;    // mutex
int rc=0;   // readers count

int writersCount;
int readersCount;
pthread_t writersThread[100], readersThread[100];
int writeCount[10], readCount[10];

void *writer(void *i)
{
    int a = *((int *) i);

    sem_wait(&w);   // P(w)
    printf("Writer %d writes to DB.\n",a+1);
    writeCount[a + 1]++;
    sem_post(&w);   // V(w)

    return NULL;
}

void *reader(void *i)
{
    int a = *((int *) i);

    sem_wait(&m);   // P(m)
    rc++;
    if (rc == 1) {
        sem_wait(&w);   // P(w)
    }
    sem_post(&m);   // V (m)

    printf("Reader %d reads from DB.\n", a + 1);
    readCount[a + 1]++;

    sem_wait(&m);   // P(m)
    rc--;
    if (rc == 0) {
        sem_post(&w);   // V(w)
    }
    sem_post(&m);   // V(m)

    return NULL;
}

int randomCount()
{
    return 5.0 * rand() / RAND_MAX;
}

int main()
{
    sem_init(&w,0,1);
    sem_init(&m,0,1);

    int i;

    printf("Enter count of writers:");
    scanf("%d",&writersCount);
    printf("Enter count of readers:");
    scanf("%d",&readersCount);

    int readerIndices[readersCount];
    int writerIndices[writersCount];
    int totalReaders = 0;
    int totalWriters = 0;

    for (i=0; i<readersCount; i++)
    {
        int j;
        int count;

        readerIndices[i] = i;
        count            = randomCount();
        for (j = 0 ; j < count ; ++j)
        {
            pthread_create(&readersThread[totalReaders++], NULL, reader, &readerIndices[i]);
        }
    }

    for (i = 0 ; i < writersCount ; i++)
    {
        int j;
        int count;

        writerIndices[i] = i;
        count            = randomCount();
        for (j = 0 ; j < count ; ++j)
        {
            pthread_create(&writersThread[totalWriters++], NULL, writer, &writerIndices[i]);
        }
    }

    for (i = 0 ; i < totalWriters ; i++)
    {
        pthread_join(writersThread[i], NULL);
    }

    for (i = 0 ; i < totalReaders ; i++)
    {
        pthread_join(readersThread[i], NULL);
    }

    printf("--------------\n");
    for (i = 0 ; i < readersCount ; i++)
    {
        printf("Reader %d read %d times\n", i + 1, readCount[i + 1]);
    }

    for (i = 0 ; i < writersCount ; i++)
    {
        printf("Writer %d wrote %d times\n", i + 1, readCount[i + 1]);
    }

    sem_destroy(&w);
    sem_destroy(&m);
    return 0;
}