Random Thoughts Random Thoughts - 1 month ago 15
C Question

Segmentation default (core dumped)

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

#define BUFFER_CAPACITY 10
#define NUMBER_OF_ITEMS_TO_PRODUCE 1000
int ring_buffer[BUFFER_CAPACITY];
size_t buffer_size = 0;
size_t producer_pointer_index = 0;
size_t consumer_pointer_index = 0;

// Defining new functions
sem_t full,empty;
pthread_mutex_t the_mutex;

void * consume(void * id);
void * produce(void * id);

int main() {
pthread_t consumer_thread1, consumer_thread2, producer_thread1, producer_thread2;

int err = pthread_create( &producer_thread1, NULL, produce, (void*)1);
if(err)
{
fprintf(stderr,"Error - pthread_create() return code: %d\n",err);
exit(EXIT_FAILURE);
}
err = pthread_create( &producer_thread2, NULL, produce, (void*)2);
if(err)
{
fprintf(stderr,"Error - pthread_create() return code: %d\n",err);
exit(EXIT_FAILURE);
}

err = pthread_create( &consumer_thread1, NULL, consume, (void*)1);
if(err)
{
fprintf(stderr,"Error - pthread_create() return code: %d\n",err);
exit(EXIT_FAILURE);
}

err = pthread_create( &consumer_thread2, NULL, consume, (void*)2);
if(err)
{
fprintf(stderr,"Error - pthread_create() return code: %d\n",err);
exit(EXIT_FAILURE);
}

// Wait till threads are complete before main continues
pthread_join( producer_thread1, NULL);
pthread_join( producer_thread2, NULL);
pthread_join( consumer_thread1, NULL);
pthread_join( consumer_thread2, NULL);

exit(EXIT_SUCCESS);
}

void * consume(void * arg) {
int id = (int) arg;
//Your Code if needed
for (int i = 0; i < NUMBER_OF_ITEMS_TO_PRODUCE; i++) {
sem_wait(&full);
pthread_mutex_lock(&the_mutex);
//critical section start
int consumed = ring_buffer[consumer_pointer_index];
consumer_pointer_index = (consumer_pointer_index + 1) % BUFFER_CAPACITY;
usleep(abs(rand())%100);
buffer_size = buffer_size - 1;
usleep(abs(rand())%100);
printf("C_%d consumed: index: %zu, \tvalue: %d, \tbuffer_size:%zu\n", id, consumer_pointer_index, consumed, buffer_size);
//critical section end

pthread_mutex_unlock(&the_mutex);
sem_post(&empty);
}

pthread_exit(0);
}


void * produce(void * arg) {
int id = *(int*) arg;
//Your Code if needed
for (int i = 0; i < NUMBER_OF_ITEMS_TO_PRODUCE; i++) {

//Your Code if needed
sem_wait(&empty);
pthread_mutex_lock(&the_mutex);
//critical section start
int produced = (i + 1) * (id * id);
ring_buffer[producer_pointer_index] = produced;
producer_pointer_index = (producer_pointer_index + 1) % BUFFER_CAPACITY;
usleep(abs(rand())%(100/id));
buffer_size = buffer_size + 1;
usleep(abs(rand())%(100/id));
printf("P_%d produced: index: %zu, \tvalue: %d, \tbuffer_size:%zu\n", id, producer_pointer_index, produced, buffer_size);
//critical section end

pthread_mutex_unlock(&the_mutex);
sem_post(&full);

}
pthread_exit(0);
}


Every time I run the program I keep getting segmentation fault, I read about it and understood that a thread is trying to read and OS is blocking it. I looked into the code to find the error, but I am having a hard time since I don't have a debugger that works well with C.

Can someone help me with this issue?

Answer

Using GDB (you should use it) you can get some good informations when your program crash.

First build the program with "-g"

gcc file.c -lpthread -g

Then run it inside gdb.

You will see this :

Thread 2 "a.out" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff781e700 (LWP 8082)]
0x0000000000400b94 in produce (arg=0x1) at test.c:84
84      int id = *(int*) arg;

From there it is pretty obvious that the guilty line is :

int id = *(int*) arg;

Let's see exactly what you are doing here :

You want to get that parameter so you can use it. That is correct...

However look at how you passed the parameter to your function :

int err = pthread_create( &producer_thread1, NULL, produce, (void*)1);

You are taking the value "1" , and casting it to void *. Why not... even though you would never really want to do that except some special cases maybe... But in your specific case it is absolutely not what you want , why ?

Because inside the produce function you think it is a pointer to and int , but it is not ! it is a number (1) converted to a void * , so on your system it my have been casted to the value (1) written on 64bits but it is still a 1. Therefore when you try to dereference it , you get a segmentation fault.

try declaring thoose values as variables and passing their adress to the pthread_create function (all of them)

EDIT

 int err = pthread_create( &producer_thread1, NULL, produce, (void*)1);

would become :

 int err = pthread_create( &producer_thread1, NULL, produce, (void*)&one);

where the variable "one" could be a global variable like this :

  int one = 1;

but it could also be an allocated int or whatever int that HAS an adress you choose.. just don't pass a value that is NOT and address and handle it as if it was.

Hope this can help.