0

I'm trying to implement a variation of the readers and writers problem in C, the variation is that writers can either be incrementers or decrementers and they should keep a running count. Below is the code I am trying to implement, I am getting the error "Segmentation Fault (core dumped). I have attempted to debug and received this feedback from gdb - #0 0x0000000000400d84 in main (). I'd appreciate it if someone were able to explain this to me/give me tips on how to fix this fault. Thanks!

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

#define WAIT 20
#define NEW 0

#define DECREMENT 0
#define INCREMENT 1

#define TIME 5
#define VALUE 1
#define COMMON 0


int readerCount = NEW;
int total = 0;
int v;
sem_t mutex;
sem_t access_data;



int increment_or_decrement() {
    int d;
    return d = rand() % 2;
}

void *writer(void *arg) {
    int version = increment_or_decrement();

    int *iID = (int *) arg;
    int *dID = (int *) arg;

    sleep(rand() % WAIT);

    sem_wait(&access_data);

    if (version == INCREMENT) {
        fprintf(stderr, "Incrementer %d accessed the data\n", *iID);
        total++;
        fprintf(stderr, "Total: %d\n", total);
    }
    else {
        fprintf(stderr, "Decrementer %d accessed the data\n", *dID);
        total--;
        fprintf(stderr, "Total: %d\n", total);
    }

    sleep(TIME);

    sem_post(&access_data);

    pthread_exit(NULL);

}


void *reader(void *arg) {
    int *id = (int *) arg;

    sleep(rand() % WAIT);

    while(1) {
        if (readerCount == NEW) {
            sem_wait(&mutex);

            v = version;
            readerCount++;

            if (readerCount == 1)
                sem_wait(&access_data);

            sem_post(&mutex);

            fprintf(stderr, "Reader %d accessed the data\n", *id);

            sem_wait(&mutex);

            readerCount--;

            if(readerCount == NEW)
                sem_post(&access_data);

            sem_post(&mutex);

            pthread_exit(NULL);
        }
    }

}


int main() {
    int numReaders = rand();
    int numWriters = rand();
    int i;

    sem_init(&mutex, COMMON, VALUE);
    sem_init(&access_data, COMMON, VALUE);

    pthread_t readers[numReaders];
    pthread_t writers[numWriters];

    int readerID[numReaders];
    int writerID[numWriters];

    for (i = 0; i < numReaders; i++)
        readerID[i] = i;

    for (i = 0; i < numWriters; i++)
        writerID[i] = i;

    for (i = 0; i < numReaders; i++) {
        if(pthread_create(&readers[i], NULL, reader, (void *) &readerID[i]) != 0) {
            printf("Child failed\n");
            exit(EXIT_FAILURE);
        }
    }

    for (i = 0; i < numWriters; i++) {
        if (pthread_create(&writers[i], NULL, writer, (void *) &writerID[i]) != 0) {
            printf("Child failed\n");
            exit(EXIT_FAILURE);
        }
    }

    for (i = 0; i < numReaders; i++) {
        if (pthread_join(readers[i], NULL) != 0) {
            printf("Join failed\n");
            exit(EXIT_FAILURE);
        }
    }

    for (i = 0; i < numWriters; i++) {
        if (pthread_join(writers[i], NULL) != 0) {
            printf("Join failed\n");
            exit(EXIT_FAILURE);
        }
    }

    sem_destroy(&access_data);
    sem_destroy(&mutex);
}
btoohey
  • 141
  • 1
  • 1
  • 12
  • 3
    `rand()` can return a sizable number. Yet thats what you're using for your thread count and array sizing, which is frankly insane. Perhaps you should restrict that down to something sane, including a floor value > 0 and less than, say, 8. And fyi, you also use `rand()` on your threads, and it is notoriously *not* thread-safe. – WhozCraig Aug 10 '17 at 03:35

2 Answers2

1

You are likely to run out of stack space if rand returns big number as indicated in comments by @WhozCraig

If you just assign some finite values instead of using rand here:

  int numReaders = rand();
  int numWriters = rand();

I see it running without segmentation fault

Pras
  • 4,047
  • 10
  • 20
0

Suspect: pthread_join(readers[i], NULL)

The second argument to pthread_join should be a valid address of a var to contain address of the return value from the exiting child threads. In this case, when a child thread exits, the pthread_exit tries to write NULL at NULL, and i think that is causing seg fault. Try changing NULL to some valid address in pthread_join for both readers and writes and see if it works.

EDIT: it turns out that POSIX allows passing NULL to pthread_join (see comments below), so suspect is acquitted.

Vikas Yadav
  • 322
  • 2
  • 9
  • The POSIX specification for [`pthread_join()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html) allows the second argument to be a null pointer, in which case no value is returned. That usage is permissible. – Jonathan Leffler Aug 10 '17 at 04:23
  • Thanks @JonathanLeffler you are right. Could it be that RAND_MAX > PTHREAD_THREADS_MAX , and so pthread_create is faulting? – Vikas Yadav Aug 10 '17 at 05:13