user1542422
user1542422

Reputation: 319

C programming Multithreading Segmentation Fault

When I run this code I just get a straight up Seg fault. I do not know how to fix it. I am trying to create a simple multithreading programming. It compiles completely fine but it when i run it by typing "./testing", the print statement "what?" at the beginning of the main function won't even print and just seg faults. I've been stuck on this for couple of hours now. Any ideas? Thanks

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

static pthread_mutex_t mutex1;
static pthread_mutex_t mutex2;

static int arrayX[4];
static int arrayY[4];

static pthread_t threads[20];

static void *function(void *index) {
    pthread_mutex_lock(&mutex1);
    int *in = (int *)index;
    arrayX[*in]++;
    pthread_mutex_unlock(&mutex1);

    pthread_mutex_lock(&mutex2);
    arrayY[*in]--;
    printf("X Finished");

    pthread_mutex_unlock(&mutex2);
}

void main() {
    printf("what?");
    //initialize the mutex
    pthread_mutex_init(&mutex1, NULL);
    pthread_mutex_init(&mutex2, NULL);

    //Initialize the arrayX
    int x = 0;
    for (x; x < 4; x++) {
        arrayX[x] = 0;
        printf("START arrayX[%d]: %d", x, arrayX[x]);
    }

    //Initialize the arrayY
    for (x = 0; x < 4; x++) {
        arrayY[x] = 0;
        printf("START arrayY[%d]: %d", x, arrayY[x]);
    }

    pthread_mutex_init(&mutex1, NULL);
    pthread_mutex_init(&mutex2, NULL);

    int *input = 0;
        for (x = 0; x < 20; x++) {
        *input = x % 4;
        pthread_create(&(threads[x]), NULL, function, input);
    }
}

Upvotes: 0

Views: 1423

Answers (1)

razz
razz

Reputation: 10100

int *input = 0 is setting the memory address of input to nullptr, therefor you can't store data in this address because it's invalid, you can simply leave it uninitialized int *input and then when you assign it to an int, the compiler would choose a suitable free memory location and assign the data to it.

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

static pthread_mutex_t mutex1;
static pthread_mutex_t mutex2;
static pthread_t threads[20];
static int arrayX[4];
static int arrayY[4];

static void *function (void *index)
{
    int in = *((int *) index);
    pthread_mutex_lock (&mutex1);
    arrayX[in]++;
    pthread_mutex_unlock (&mutex1);
    pthread_mutex_lock (&mutex2);
    arrayY[in]--;
    pthread_mutex_unlock (&mutex2);
    // printf ("X Finished\n");
}

int main (int argc __attribute__((unused)), char **argv __attribute__((unused)))
{
    int x = 0;
    int *input;

    printf ("what?\n");
    // Initialize the mutex
    pthread_mutex_init (&mutex1, NULL);
    pthread_mutex_init (&mutex2, NULL);
    // Initialize arrayX and arrayY
    memset (arrayX, 0, sizeof (arrayX));
    memset (arrayY, 0, sizeof (arrayY));
    // Increment values inside arrays
    for (x = 0; x < 20; x++)
    {
        *input = x % 4;
        pthread_create (&(threads[x]), NULL, function, input);
    }
    // Print array values
    for (x = 0; x < 4; x++) printf ("arrayX[%d]: %d\n", x, arrayX[x]);
    for (x = 0; x < 4; x++) printf ("arrayY[%d]: %d\n", x, arrayY[x]);

    return 0;
}

Edit:

Dereferencing (which means using * operater to asign value to an already declared pointer i.e. *ptr = something) an uninitialized pointer (which means declaring a pointer without assigning value to it i.e. int *pointer;) is not a good pratice, although it may work but it can cause a crash sometimes, this is because the uninitialized pointer may point to a memory address that is being used by the system will cause an Undefined Behaviour and possibly a crash. A corret approach would be to initialize the pointer to NULL or use malloc to get a valid pointer, however when you initialize a pointer to NULL you can not dereference it becuase it's an invalid pointer.

So instead of doing:

int *input;
*input = x % 4;

We can do:

int *input;
input = malloc (sizeof (int));
*input = x % 4;

When sending input pointer to one thread then changing its value and sending it to another thread, the input value would be changed in the first thread to the new value as well, this happens because you are sharing the same pointer input (therefore the same memory address) with all the threads. To make sure that every thread gets the intended input value you can do:

for (x = 0; x < 20; x++)
{
    // Create a new valid pointer
    input = malloc (sizeof (int));
    *input = x % 4;
    pthread_create (&(threads[x]), NULL, function, input);
}

This will pass a different pointer to each thread, However when you dynamically allocate memory using malloc for example, you have to free this allocated memory, we can do that from within each thread:

static void *function (void *index)
{
    int *in = (int *) index;

    pthread_mutex_lock (&mutex1);
    arrayX[*in]++;
    pthread_mutex_unlock (&mutex1);

    pthread_mutex_lock (&mutex2);
    arrayY[*in]--;
    printf ("X Finished");
    pthread_mutex_unlock (&mutex2);

    // Freeing the allocated memory
    free (in);
}

When creating threads using pthread_creat, the main threads terminates when it hits the end of the main function without waiting for the other threads to finish work, unless you tell the main thread to wait for them, to do that we can use pthread_join:

// Create new threads
for (x = 0; x < 20; x++)
{
    *input = x % 4;
    pthread_create (&(threads[x]), NULL, function, (void *) input);
}
// Wait for the threads to finish
for (x = 0; x < 20; x++)
{
    pthread_join (threads[x], NULL);
}

This will force the main thread to keep running until all the other threads has done their work before it exits.

Upvotes: 1

Related Questions