0

I'm currently being introduced to the concept of threading programs, and have been given an assignment to simulate a stockmarket using threads and semaphores. Here is the code:

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

This is giving me a segmentation fault pretty much as soon as main() begins, with the creation of a thread... Since it's not code that I've created from root, I'm having trouble backtracing the error and fixing it - it would be great if there was someone who could take a look and maybe give me some hints

Thank you!

EDIT

Fixed the problem, thanks to your help :)

I initialized stocklist on init(),

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

And changed the second cicle in main(),

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

Thanks

M. M. F.
  • 35
  • 10
  • Another hint: revert to empty `main()` and add back pieces of code until you find which one produces fault. – Victor Sorokin Oct 07 '14 at 19:59
  • Yet another hint - debuggers such as gdb can tell you exactly where the segmentation fault is happening. Just compile the program with a -g flag, and then run run the executable from gdb. – Gillespie Oct 07 '14 at 20:09
  • stocklist does not appear to ever be initialized, which would cause an issue. – Cryo Oct 07 '14 at 20:10
  • `stocklist` is a pointer to a structure but was never allocated a memory. threads for READERS will never get created because `j` will start at 5 and `NUM_READERS` is 5. – alvits Oct 07 '14 at 20:28
  • Why are you terminating the main thread with pthread_exit(NULL)? – Martin James Oct 07 '14 at 21:33
  • 1
    @Cryo That was the main issue, yes - I was just uncertain of how I should initialize it properly. I ended up initializing it within the init() function and it worked, thanks! – M. M. F. Oct 08 '14 at 06:18
  • @alvits Fixed those two issues and it's working, thank you! – M. M. F. Oct 08 '14 at 06:19
  • @MartinJames pthread_exit(NULL) is supposed to terminate the main thread once it has done its job, of creating both the writer and the reader threads. At least that's the way I understood it, but I might be thinking wrong – M. M. F. Oct 08 '14 at 06:21

1 Answers1

2

Here's what I did to track down the problem:

gcc -g program.c -lpthread

gdb a.out

run

Output:

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;

Looks like the problem is here:

stocklist->slots[stock] = stock_value;

Gillespie
  • 5,780
  • 3
  • 32
  • 54
  • That's right - turns out the main error was that stocklist wasn't initialized, so it couldn't be accessed anyways – M. M. F. Oct 08 '14 at 06:15