Ошибка сегментации в многопоточной программе C-потребитель-производитель

В настоящее время я знакомлюсь с концепцией многопоточных программ и получил задание смоделировать фондовый рынок с использованием потоков и семафоров. Вот код:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <pthread.h>

#define NUM_WRITERS 5   
#define NUM_READERS 5   
#define STOCKLIST_SIZE 10  

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
sem_t stop_writers;

typedef struct
{   int readers;
    int slots[STOCKLIST_SIZE];
} mem_structure;

int id[NUM_READERS + NUM_WRITERS];
mem_structure *stocklist;
pthread_t thr[NUM_WRITERS + NUM_READERS];

void init(){
    sem_init(&stop_writers, 0, 1);
}

void cleanup(int signo) // clean up resources by pressing Ctrl-C
{   sem_destroy(&stop_writers);
    printf("Closing...\n");
    exit(0);
}


void write_stock(int n_writer)
{
    int stock = (int)(rand()%STOCKLIST_SIZE);
    int stock_value = 1 + (int)(100.0 * rand()/(RAND_MAX + 1.0));
    stocklist->slots[stock] = stock_value;
    fprintf(stderr, "Stock %d updated by BROKER %d to %d\n", stock, n_writer, stock_value);
}

void* writer(void* id){
    int my_id = *((int*) id);
    int i = my_id;

    while (1)
    {
        pthread_mutex_lock(&mutex);
        sem_wait(&stop_writers);
        write_stock(i);
        pthread_mutex_unlock(&mutex);
        sem_post(&stop_writers);

        sleep(1);
        ++i;
    }

}

void read_stock(int pos, int n_reader){
    fprintf(stderr, "Stock %d read by client %d = %d.\n", pos, n_reader, stocklist->slots[pos]);
}

void* reader(void* id){
    int my_id = *((int*) id);
    int i = my_id;

    while (1)
    {   sem_wait(&stop_writers);
        read_stock((int)(rand()%STOCKLIST_SIZE), i);
        sem_post(&stop_writers);
        sleep(1 + (int) (3.0 * rand() / (RAND_MAX + 1.0)));
        ++i;
    }
}

void monitor() // main process monitors the reception of Ctrl-C
{
    struct sigaction act; 
    act.sa_handler = cleanup; 
    act.sa_flags = 0; 
    if ((sigemptyset(&act.sa_mask) == -1) || 
        (sigaction(SIGINT, &act, NULL) == -1)) 
        perror("Failed to set SIGINT to handle Ctrl-C");
    while(1){
        sleep(5);
        printf("Still working...\n");
        }
    exit(0);
    }


int main(void)
{   int i, j;
    init();

    for (i = 0; i < NUM_WRITERS; ++i){
        id[i] = i;
        pthread_create(&thr[i], NULL, writer, &id[i]);}
    for (j = i; j < NUM_READERS; ++j){
        id[j] = j;
        pthread_create(&thr[j], NULL, reader, &id[j]);}

    stocklist->readers = 0;
pthread_exit(NULL);

    monitor();
    return 0;
}

Это дает мне ошибку сегментации почти сразу, как начинается main() с созданием потока... Поскольку это не код, который я создал из root, у меня возникают проблемы с отслеживанием ошибки и ее исправлением - было бы здорово, если бы нашелся кто-то, кто мог бы посмотреть и, возможно, дать мне несколько советов

Спасибо!

ИЗМЕНИТЬ

Проблема решена, благодаря вашей помощи :)

Я инициализировал список акций в init(),

void init(){
    sem_init(&stop_writers, 0, 1);
    stocklist = (mem_structure*)malloc(sizeof(mem_structure));
}

И изменил второй цикл в main(),

for (j = i; j < NUM_READERS+NUM_WRITERS; ++j){
    id[j] = j;
    pthread_create(&thr[j], NULL, reader, &id[j]);}

Спасибо


person M. M. F.    schedule 07.10.2014    source источник
comment
Еще один совет: вернитесь к пустому main() и добавляйте обратно фрагменты кода, пока не найдете, какой из них вызывает ошибку.   -  person Victor Sorokin    schedule 07.10.2014
comment
Еще один совет: отладчики, такие как gdb, могут точно указать, где происходит ошибка сегментации. Просто скомпилируйте программу с флагом -g, а затем запустите исполняемый файл из gdb.   -  person Gillespie    schedule 08.10.2014
comment
stocklist, похоже, никогда не инициализируется, что может вызвать проблему.   -  person Cryo    schedule 08.10.2014
comment
stocklist — это указатель на структуру, но никогда не выделялась память. потоки для READERS никогда не будут созданы, потому что j начнется с 5, а NUM_READERS будет 5.   -  person alvits    schedule 08.10.2014
comment
Почему вы завершаете основной поток с помощью pthread_exit(NULL)?   -  person Martin James    schedule 08.10.2014
comment
@Cryo Это была главная проблема, да - я просто не знал, как правильно ее инициализировать. В итоге я инициализировал его в функции init(), и это сработало, спасибо!   -  person M. M. F.    schedule 08.10.2014
comment
@alvits Исправлены эти две проблемы, и все работает, спасибо!   -  person M. M. F.    schedule 08.10.2014
comment
Предполагается, что @MartinJames pthread_exit(NULL) завершает основной поток после того, как он выполнил свою работу по созданию потоков записи и чтения. По крайней мере, я так понял, но может быть я ошибаюсь   -  person M. M. F.    schedule 08.10.2014


Ответы (1)


Вот что я сделал, чтобы отследить проблему:

gcc -g program.c -lpthread

gdb a.out

run

Выход:

Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xb7feeb70 (LWP 23060)] 0x08048834 in write_stock (n_writer=0) at program.c:44 44 stocklist->slots[stock] = stock_value;

Похоже, проблема здесь:

stocklist->slots[stock] = stock_value;

person Gillespie    schedule 07.10.2014
comment
Правильно - оказывается, основная ошибка заключалась в том, что список акций не был инициализирован, поэтому к нему все равно нельзя было получить доступ - person M. M. F.; 08.10.2014