LiquidSpirit
LiquidSpirit

Reputation: 1

Getting segmentation fault and varying output when running program

I have a program that is supposed to copy the contents of a file exactly to another file using multiple threads. The reader thread reads a line from the file and stores it in a circular buffer. The writer thread then reads from the buffer and writes to the file. However I am getting a segmentation fault and it is not writing to the file. Any idea why I am getting a segmentation fault or is there any way that I can find out what is causing the error?

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

FILE *inputFile;
FILE *outputFile;

pthread_mutex_t mutex;

int endOfFile = 0;

typedef struct bufferStruct{
    int capacity;
    int size;
    int head;
    int tail;
    char **data;
}buffer;

buffer * bufferInit(int maxElements){
    buffer *buf;
    buf = (buffer *)malloc(sizeof(buffer));

    buf->data = (char**)malloc(sizeof(char*)*maxElements);
    buf->size = 0;
    buf->capacity = maxElements;
    buf->head = 0;
    buf->tail = -1;

    return buf;
}

void popFront(buffer *buf){
    if(buf->size != 0){
        free(buf->data);
        buf->size--;
        buf->head++;
        if(buf->head == buf->capacity){
            buf->head = 0;
        }
    }
    return;
}

char* front(buffer *buf){
    if(buf->size != 0){
        return buf->data[buf->head];
    }

    return NULL;
}

void pushBack(buffer *buf, char *data){
    if(buf->size == buf->capacity){
        printf("Queue is Full\n");
    }

    else{
        buf->size++;
        buf->tail = buf->tail + 1;

        if(buf->tail == buf->capacity){
            buf->tail = 0;
        }

        buf->data[buf->tail] = (char *) malloc((sizeof data + 1)* sizeof(char));

        strcpy(buf->data[buf->tail], data);
    }
    return;
}

buffer *buf;

void* reader(void* arg){
    char line[1024];
    while(endOfFile != 1){
        fgets(line, sizeof(line), inputFile);
        printf("Line read: %s", line);

        pushBack(buf, line);

        if(feof(inputFile)){
            endOfFile = 1;
        }
    }
    pthread_exit(0);
}

void* writer(void* arg){
    char *line;
    while(endOfFile != 1){
        pthread_mutex_lock(&mutex);
        line = front(buf);
        fputs(line, outputFile);
        popFront(buf);
        pthread_mutex_unlock(&mutex);
    }
    pthread_exit(0);
}

int main(int argc, char **argv){
    if (argc < 4) {
        printf("Usage: %s <input file> <output file> <number>\n", argv[0]);
        exit(-1);
    }

    inputFile = fopen(argv[1], "r");
    outputFile = fopen(argv[2], "w");
    int numOfThreads = atoi(argv[3]);

    buf = bufferInit(16);

    pthread_t readerTids[numOfThreads];
    pthread_t writerTids[numOfThreads];

    pthread_mutex_init(&mutex, NULL);

    for(int i = 0; i < numOfThreads; i++){
        if(endOfFile != 1){
            pthread_attr_t attr;
            pthread_attr_init(&attr);
            pthread_create(&readerTids[i], &attr, reader, NULL);
            pthread_create(&writerTids[i], &attr, writer, NULL);

            printf("Thread %d created\n", i);
        }
    }

    for (int i = 0; i < numOfThreads; i++) {
        pthread_join(readerTids[i], NULL);
        pthread_join(writerTids[i], NULL);
    }

    fclose(inputFile);
    fclose(outputFile);
}

Upvotes: 0

Views: 65

Answers (1)

RohitMat
RohitMat

Reputation: 165

Consider the possibility of your reader thread being slower than the writer thread. The writer thread alone holds the lock, does the locking and unlocking, not being bothered about the reader. What if the writer tries to use the buffer when reader hasn't updated the buffer yet? Use thread synchronisation, say semaphores, which does not have any ownership issues.

void* reader(void* arg){
    char line[1024];
    while(endOfFile != 1){
        fgets(line, sizeof(line), inputFile);
        printf("Line read: %s", line);

        pushBack(buf, line);

--- Lock semaphore here---

        if(feof(inputFile)){
            endOfFile = 1;
        }
    }
    pthread_exit(0);
}


void* writer(void* arg){
    char *line;
    while(endOfFile != 1){

-- Unlock semaphore here---

        line = front(buf);
        fputs(line, outputFile);
        popFront(buf);
    }
    pthread_exit(0);
}

Unlike mutex, the same semaphore can be used between both threads. This helps you to sync up both threads.

Upvotes: 1

Related Questions