0

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);
    }
}
user1542422
  • 133
  • 1
  • 2
  • 11
  • It does print, you forgot to print a newline (`\n`). Btw, I figured that out by commenting out all code in `main` except the `printf("what?");`. – Kenney Nov 09 '15 at 00:14
  • It looks like your function has no name? static void *function(void *index) – PeteB Nov 09 '15 at 00:15
  • Oh Thanks. lol I'lll keep debugging – user1542422 Nov 09 '15 at 00:16
  • 1
    `int *input = 0; *input = x % 4;`. That dereferences an invalid pointer. – kaylum Nov 09 '15 at 00:16
  • Cool, I fixed it by doing, int input = 0, input = x% 4 and then inside the pthread_create function I did %input. Thanks!! – user1542422 Nov 09 '15 at 00:20
  • 1
    That may fix the crash but it's not functionally correct. 1. It will end up giving every thread the same `input` value. 2. Your main function needs to wait for the threads to complete with `pthread_join` otherwise it will exit the process immediately after all the `pthread_create` calls and hence also prematurely kill all the threads. – kaylum Nov 09 '15 at 00:23
  • use `int main()` instead of `void main()` [What should main() return in C and C++?](http://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c) – razz Nov 09 '15 at 00:28
  • @razzak you should probably use `int main(void)` in C. Otherwise C programmers will complain about it. – Bobby Sacamano Nov 09 '15 at 00:42
  • @user1542422 Have a look at my updated answer, it addresses the issues pointed out by [kaylum](http://stackoverflow.com/users/3003365/kaylum) in the comments above – razz Nov 09 '15 at 22:05

1 Answers1

1

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.

razz
  • 8,452
  • 6
  • 45
  • 61
  • `*input = x % 4;`. That is dereferencing an unitialised pointer. And see my comment regarding passing `input` to each thread. That is not functionally correct as all threads are likely to end up with the same `input` value (the last value set). – kaylum Nov 09 '15 at 02:39
  • Looks much better. But please remove this: "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.". Accessing uninitialised variables is **always** incorrect (note: some storage classes are automatically initialised but not in this case). There is no "may" or "sometimes". – kaylum Nov 09 '15 at 22:18
  • can you give me a reference about this, i read [A B](http://stackoverflow.com/users/1298874/a-b) answer for this SO [question](http://stackoverflow.com/questions/14224831/meaning-of-referencing-and-dereferencing) and he said it `may or may not` cause a crash, so i'm a bit confused. – razz Nov 09 '15 at 22:28
  • 1
    The reference is the C standard :-) It describes Undefined Behaviour (which includes accessing unintialised variables). UB means that anything can happen - including appearing to work. But UB code is always wrong. There are many answers to this on SO. Some: [Undefined, unspecified and implementation-defined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) and [Does “Undefined Behavior” really permit *anything* to happen?](https://stackoverflow.com/questions/32132574/does-undefined-behavior-really-permit-anything-to-happen) – kaylum Nov 09 '15 at 22:33
  • 1
    Put another way - would you consider a program that "may or may not" crash "working"? The answer must be NO. "Working" code must function correctly all the time, not some of the time. – kaylum Nov 09 '15 at 22:37
  • I didn't know about `UB` before i'm not very advanced in `c`, thanks to all your comments they were very informative :). I updated my answer. – razz Nov 09 '15 at 22:56