1

I have a few problems I can't solve in implementing WRITER-READER problem in UNIX. First one is that I have no idea, how can I modify the code to work like threads are always calling to enter reading room. For example, when a writer is in the reading room, readers are waiting to access the reading room. When writer is escaping the reading room and readers are entering the reading room, he still is waiting for his chance. The second one is that I have no idea how to modify the code to allow a few readers to enter the reading room. In my code only one thread can be in the same time in the reading room. The third one is, how to recognize if writer or reader is starving? Which one is starving in my code?

Here is the code:

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

#define READERS 15
#define WRITERS 10

int bufferw = 0, bufferr = 0, counterw = WRITERS, counterr = READERS;
int i;

pthread_mutex_t mwrite, mread;
pthread_cond_t condw, condr;
pthread_t r[READERS], w[WRITERS];

void *writer(void *ptr) {

    pthread_mutex_lock(&mwrite);

    {
      counterr = READERS;
      counterw = WRITERS;
      ++bufferw;    

     for(i=0; i<READERS; i++) while(bufferr > 0) pthread_cond_wait(&condw, &r[i]);

      printf("WRITER ENTERING!");

      pthread_mutex_unlock(&mwrite);

      bufferw--;
    }

    pthread_cond_signal(&condr);

    pthread_exit(0);
}

void *reader(void *ptr) {

    counterr = READERS;
    counterw = WRITERS;

    {
      ++bufferr;

      for(i=0; i<WRITERS; i++) while(bufferw == 1) pthread_cond_wait(&condr, &w[i]);

      printf("READER ENTERING!");

      bufferr = 0;
    }

    pthread_cond_signal(&condw);
    pthread_exit(0);
}


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

    pthread_mutex_init(&mwrite, 0);
    pthread_mutex_init(&mread, 0);

    pthread_cond_init(&condw, 0);
    pthread_cond_init(&condr, 0);

    for(i=0; i<WRITERS; i++) pthread_create(&w[i], NULL, writer, NULL);
    for(i=0; i<READERS; i++) pthread_create(&r[i], NULL, reader, NULL);

    for(i=0; i<WRITERS; i++) pthread_join(w[i], NULL);
    for(i=0; i<READERS; i++) pthread_join(r[i], NULL);

    pthread_cond_destroy(&condw);
    pthread_cond_destroy(&condr);
    pthread_mutex_destroy(&mwrite);
    pthread_mutex_destroy(&mread);

 return 0;
}

Thanks in advance for your help!

EDIT:// How can I avoid race in this case?

Claudio
  • 10,614
  • 4
  • 31
  • 71
  • I'm a bit lost here. You have "writers" that don't write, and "readers" that don't read. What's the goal? (And don't you think the way there would be clearer if the two types of threads did something of consequence?) – cHao Jan 09 '15 at 21:11
  • where are arguments to pthread_cond_wait defined? – Jasen Jan 09 '15 at 21:14
  • It is only simulation. :) Writer is a thread, who only can be alone in the reading room, readers can be a lot in the reading room, but not when the writer is inside. :) they don't need to read, or write something. (I think so). –  Jan 09 '15 at 21:14
  • @Jasen, are they essential? –  Jan 09 '15 at 21:16
  • Why not use pthread_rwlock_t and the associated functions? – Arlie Stephens Jan 09 '15 at 21:17
  • @Arlie Stephens, I did not hear about these functions. But I just read about it, but I don't know how could they help me. –  Jan 09 '15 at 21:23
  • if you're calling pthread_cond_wait on something you didn't lock you get undefined behaviour – Jasen Jan 09 '15 at 21:29
  • this kind of line: 'pthread_cond_wait(&condr, &mwrite);' Note the second parameter is the address of a pthread_mutex_t, not the address of a pthread_t – user3629249 Jan 09 '15 at 21:43
  • the 'bufferw' and 'bufferr' common/global variables are being modified outside the protection of a mutex. Therefore, there will be race conditions resulting in corruption of those values. – user3629249 Jan 09 '15 at 21:46
  • the 'counterw' and 'counterr' common/global variables are being set outside the protection of a mutex. Those variables are never being used. The compiler will fail to warn, however the general idea is to not have variables that are only set and never used. – user3629249 Jan 09 '15 at 21:52
  • the race conditions can be avoided by performing all modification of those global/common variables after the mutex lock and before the mutex unlock function calls. – user3629249 Jan 09 '15 at 21:54
  • you can have multiple active readers by using a counting semaphore, – user3629249 Jan 09 '15 at 21:57
  • in general, since the readers and the writers are accessing (or should be accessing) the same resource 1) they should all be using the same mutex 2) all data manipulation should be performed inside the confines of that mutex protected code sequence(s) – user3629249 Jan 09 '15 at 22:02
  • re pthread_rwlock_t - this should be a prepackaged implementation of what you want. Your reader and writer just have to get the lock in the appropriate mode, and it's all done for you. What I don't know is which way the starvation goes. – Arlie Stephens Jan 09 '15 at 22:11
  • @user3629249, wow, thank you for your answer! It really helped me with understanding the code. :) –  Jan 09 '15 at 22:12

1 Answers1

3

you could use one mutex and two conditional variables to implement this.

reader( ) {
     pthread_mutex_lock(&m);
     while (!(writers == 0))
     pthread_cond_wait(&readersQ, &m);
     readers++;
     pthread_mutex_unlock(&m);

     /* actual read */

     pthread_mutex_lock(&m);
     if (--readers == 0)
     pthread_cond_signal(&writersQ);
     pthread_mutex_unlock(&m);
    }



writer( ) {
 pthread_mutex_lock(&m);
 writers++;
 while (!((readers == 0) && (active_writers == 0))) {
 pthread_cond_wait(&writersQ, &m);
 }
 active_writers++;
 pthread_mutex_unlock(&m);

 /* actual write */

 pthread_mutex_lock(&m);
 writers--;
 active_writers--;
 if (writers > 0)
   pthread_cond_signal(&writersQ);
 else
   pthread_cond_broadcast(&readersQ);
 pthread_mutex_unlock(&m);
}

This implementation is unfair to the readers, which means if there is a writer writing, readers will never get a choice to read. This is because writing is more important than reading. If you don't think so, I can also provide a version which is unfair to writers.

The reader will get a choice to read only when writers are equal to zero. If there is a single writer, the writer will not be zero and the reader cannot read.

If there are multiple writers, the variable active_writers will make sure that only one writer could write at a time.

EDIT

below is the version starve writers. For the reader, it is the same code.

writer( ) {
 pthread_mutex_lock(&m);
 while(!((readers == 0) &&(writers == 0)))
     pthread_cond_wait(&writersQ, &m);
 writers++;
 pthread_mutex_unlock(&m);

 /* actual write */

 pthread_mutex_lock(&m);
 writers--;
 pthread_cond_signal(&writersQ);
 pthread_cond_broadcast(&readersQ);
 pthread_mutex_unlock(&m);
}
Holger
  • 285,553
  • 42
  • 434
  • 765
qqibrow
  • 2,942
  • 1
  • 24
  • 40
  • i actually need 3 solutions of this problem: 1 with readers starving, 1 with writers starving and 1 without any starving and also one of this solution must use condition variables. :) –  Jan 09 '15 at 21:51
  • I provide the unfair to reader version. I don't have one fair to everyone off top of my head. – qqibrow Jan 09 '15 at 22:33