A variation of the Seqlock algorithm

advertisements

Can someone provide some examples/tips/indications of how to solve the following assignment: a resource may be used by 2 types of processes: black and white. When the resource is used by the white processes, it can not be used by the black processes and vice-versa. Implement the access to the resource avoiding starvation. In an older post I was advised to use a variation on the seqlock algorithm, but I can't figure how to adjust that algorithm for this assignment.

EDIT: this is the code I've written so far

#include <stdio.h>
#include <pthread.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>

struct RW;
struct RW
{
    volatile int num_reads_in_progress;
    volatile int num_writes;
    pthread_cond_t reader_cv;
    pthread_cond_t writer_cv;
    pthread_mutex_t lock;
};
char *buf;
void signal_next(struct RW *b);
extern char *xx_read(struct RW *);
extern void xx_write(struct RW *, char *); 

// Precondition: b->lock must be locked before this function is called
void signal_next(struct RW *b)
{
    if (b->num_writes > 0)
    {
        // if any writes are waiting wake one up
        pthread_cond_signal(&b->writer_cv);
    }
    else
    {
        // if are no writes pending, wake up all the readers
        pthread_cond_broadcast(&b->reader_cv);
    }
}

void *ts_read(void *vb);
void *ts_read(void *vb)
{
    struct RW *b = vb;
    pthread_mutex_lock(&b->lock);
    while (b->num_writes > 0)
    {
        // cond_wait unlocks the mutex, waits to be signaled, then re-acquires the mutex
        pthread_cond_wait(&b->reader_cv, &b->lock);
    }
    // By there b->num_writes must be 0
    b->num_reads_in_progress++;
    pthread_mutex_unlock(&b->lock);

    buf = xx_read(b); 

    pthread_mutex_lock(&b->lock);
    b->num_reads_in_progress--;
    signal_next(b);
    pthread_mutex_unlock(&b->lock);
    return 0;
}

void *ts_write(void *vb);
void *ts_write(void *vb)
{
    struct RW *b = vb;
    pthread_mutex_lock(&b->lock);
    b->num_writes++;

    if (b->num_writes > 1 || b->num_reads_in_progress > 0)
    {
        // cond_wait unlocks the mutex, waits to be signaled,
        // then re-acquires the mutex
        pthread_cond_wait(&b->writer_cv, &b->lock);
    }
    pthread_mutex_unlock(&b->lock);

    xx_write(b, buf);
    pthread_mutex_lock(&b->lock);
    b->num_writes--;
    signal_next(b);
    pthread_mutex_unlock(&b->lock);
    return 0;
}

int main(void)
{
    pthread_t white[3];
    pthread_t black[3];
    struct RW *rw;
    rw = malloc(sizeof(struct RW));
    int i;
    for (i = 0; i < 3; i++)
    {
        pthread_create(&white[i], NULL, &ts_read, &rw);
    }

    for (i = 0; i < 3; i++)
    {
        pthread_create(&black[i], NULL, ts_write, &rw);
    }
    for (i = 0; i < 3; i++)
    {
        pthread_join(white[i], NULL);
    }
    for (i = 0; i < 3; i++)
    {
        pthread_join(black[i], NULL);
    }
    return 0;
}


You need a Mutex that locks and unlocks. Basically you can think of a mutex as a boolean value that is either true or false(locked or unlocked if you prefer).

When black process accesses the resource, the mutex should be locked. And, on the other hand when white tries to access it, it should first check for the mutex's status. If the status of mutex is locked, then it will have to wait until the mutex is unlocked.

Pseudocode:

unsigned char mutex = 0;

//processBlack tries to access resource
  if(mutex == 1)
      while(mutex != 0);
  mutex = 1;
  //now the mutex is unlocked, do whatever you want
  mutex = 0; //do not forget to unlock it.

//processWhite tries to access resource
  if(mutex == 1)
      while(mutex != 0);
  mutex = 1;
  //now the mutex is unlocked, do whatever you want
  mutex = 0; //do not forget to unlock it.