Christopher Bell Christopher Bell - 1 month ago 7
C Question

Thread return value is inconsistent with expected output

I'm working on a project that requires somewhat similar functionality to the program below so I've tried to create a simpler program to debug my larger program. The threads I'm creating are returning values that are inconsistent with their expected output but their return values are not random. It almost seems like the threads are returning the values from other threads or that the variable they are returned to ("tmp") is updating.

The expected output should be...

0 1

1 2

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

struct Numbers {
int x;
int y;
};

void *go(void* param)
{
struct Numbers* nums = (struct Numbers*) param;
int sum = nums -> x + nums -> y;

return (void*) sum;
}

int main()
{
int result[2][2];
int tmp;

pthread_t thread[2][2];

int i, j;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
struct Numbers nums;
nums.x = i;
nums.y = j;

pthread_create(&thread[i][j], NULL, go, &nums);
}
}

for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
pthread_join(thread[i][j], (void*) &tmp);
result[i][j] = tmp;
}
}

for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
printf("%d\t", result[i][j]);
}
printf("\n");
}

return 0;
}

Answer

You're passing the address of a variable that probably won't exist once the thread begins executing, or at least will be seen by multiple threads, or is a data race as one thread writes it while the others read it.

A general solution is to dynamically allocate both the arguments and results of your thread, and let the caller and thread communicate that way.

Example:

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

struct threadargs {
    int x;
    int y;
};

struct threadresults {
    int sum;
    int product;
};

void* threadfunc(void* args_void) {
    // Get thread args in usable type.
    struct threadargs* args = args_void;
    struct threadresults* results = NULL;

    //Compute.
    int sum = args->x + args->y;
    int product = args->x * args->y;

    // Return the result.    
    results = malloc(sizeof(*results));
    results->sum = sum;
    results->product = product;

    free(args);
    return results;
}

int main()
{
    pthread_t thread[2][2];
    struct threadresults* results[2][2] = {0};

    int i, j;
    for (i = 0;i < 2; ++i) {
        for (j = 0; j < 2; ++j) {
            struct threadargs* args = malloc(sizeof(*args));
            args->x = i;
            args->y = j;

            pthread_create(&thread[i][j], NULL, threadfunc, args);
        }
    }

    for (i = 0; i < 2; i++) {
        for (j = 0; j < 2; j++) {
            void* result;
            pthread_join(thread[i][j], &result);
            results[i][j] = result;
        }
    }

    for (i = 0; i < 2; i++) {
        for (j = 0; j < 2; j++) {
            printf("sum: %d\tproduct: %d\n",
                   results[i][j]->sum, results[i][j]->product);
        }
    }

    for (i = 0; i < 2; i++) {
        for (j = 0; j < 2; j++) {
            free(results[i][j]);
        }
    }

    return 0;
}