运行程序时出现分段错误并改变输出

问题描述:

我有一个程序应该将文件的内容完全复制到使用多个线程的另一个文件中。阅读器线程从文件中读取一行并将其存储在循环缓冲区中。写入器线程然后从缓冲区读取并写入文件。但是,我收到了分段错误,并且没有写入文件。任何想法为什么我得到一个分段错误,或者有什么办法,我可以找出是什么导致了错误?运行程序时出现分段错误并改变输出

#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); 
} 
+0

阅读[未定义的行为](https://en.wikipedia.org/wiki/Undefined_behavior)。躲开它。详细了解[pthreads](https://computing.llnl.gov/tutorials/pthreads/)。编译所有警告和调试信息('gcc -Wall -Wextra -g')。使用调试器('gdb')来了解更多关于分段错误的信息。也可以使用[valgrind](http://valgrind.org/)。你的* fix-my-code *问题是无关紧要的。它看起来像你的线程不够同步(你可能需要一个互斥体)。 –

+2

您的读者线程永远不会锁定互斥锁,这意味着您的读者线程可以随时修改(buf),即使写入者线程锁定了互斥锁。因此你的程序有一个*竞争条件*并且遇到未定义的行为。 (另外,你的两个线程都会在没有任何同步的情况下访问全局变量'endOfFile',这也会导致未定义的行为) –

+0

@JeremyFriesner给了你答案,顺便说一句,你可以使用Semaphore来“简化”syncronization而不是互斥 – Raskayu

考虑到读者线程比写入者线程慢的可能性。作家线程独自拥有锁定,锁定和解锁,而不是困扰读者。当阅读器尚未更新缓冲区时,如果作者试图使用缓冲区,该怎么办?使用线程同步,例如信号量,它没有任何所有权问题。

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); 
} 

与互斥锁不同,两个线程之间可以使用相同的信号量。这可以帮助你同步两个线程。