1

I'm trying to pass pointers to struct lower_hyper_id from a thread to the main thread, by the means of pthread_exit() function, that would compare and output the value in the struct. However, i receive an error (Segmentation fault) when i am trying to use the returned value and cast it to the struct.

thread that creates and returns the struct:

void *compute(void *arg){
   lower_hyper_id *data = (lower_hyper_id *)malloc(sizeof(lower_hyper_id));

   //some code
   //i debug the program, and at this point, the struct i want
   //to return has the values i want.

   pthread_exit((void *)data);
}

in the main:

lower_hyper_id l_hyper_id;

int main(){
    void *ap_state;
    lower_hyper_id values;
    void *ret;

    //some code

    for (int i = 0; i < NUMBER_OF_FILTERING_THREADS; i++)
    {
        s = pthread_join(filtering_threads[i], (void *)&ret);
        //some error checking 

        values = *((lower_hyper_id *)ret);  //this is where i receive the error

        if (values.lowest_cost <= l_hyper_id.lowest_cost)
        {
            l_hyper_id.hyper_id = values.hyper_id;
            l_hyper_id.lowest_cost = values.lowest_cost;
        }
        free(ret);
}

I have already looked at answers in the stackoverflow such as this question, but it hasn't helped me resolving this. I actually changed the code to be exactly equal to the code in this answer, but still it gives me an error.

Diogo Soares
  • 130
  • 2
  • 8
  • Do you test `ret` against `NULL` *before* dereferencing it? – alk May 19 '19 at 09:17
  • @alk indeed... i tried it and if i do if(ret == NULL), the ret is NULL. any way to fix this? – Diogo Soares May 19 '19 at 09:33
  • No idea, well, I could guess, what I won't, as you do not show the complete/relevant code. – alk May 19 '19 at 09:38
  • 1
    Probably unrelated but casting `&ret` to `void*` is useless and misleading. `pthread_join` expects a `void**`, which `&ret` is. – n. m. could be an AI May 19 '19 at 09:43
  • 1
    Check for early returns in `compute`. – n. m. could be an AI May 19 '19 at 09:47
  • 1
    Few, if any, of the casts in this thing are needed, and they have every reason *not* to be in the code. Get rid of them. More characters != better code. Also, strip all of the `// some code` code you concluded couldn't possibly be part of your problem. Alloc some memory, start a do-nothing thread with pointer to that memory as the user-arg, return that pointer through `pthread_exit`, and reap it from `pthread_join`. If you can't make that work `// some code`is irrelevant. Further, if you *can* make that work, then `// some code` is the *problem*. – WhozCraig May 19 '19 at 09:47

1 Answers1

0

You're not testing if malloc returned NULL. That could be an issue if you're allocing a large chunk and the allocation can fail. Other than that, I don't think the problem is in the return value passing.

pthread_exit()ing with a mallocd pointer should work just fine.

A minimial working example:

#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *compute (void *arg)
{
    printf("thread=%llx\n", (unsigned long long)pthread_self());
    size_t sz = strlen("hello world")+1;
    char *ret = malloc(sz+1);
    if(ret) memcpy(ret, "hello world", sz+1);
    return ret;
}
int main()
{
    printf("thread=%llx\n", (unsigned long long)pthread_self());
    pthread_t ptid;
    int er;
    if((er=pthread_create(&ptid,0,compute,0))) return errno=er,perror(0),1;
    void *retval;
    if((er=pthread_join(ptid,&retval))) return errno=er,perror(0),1;
    printf("thread returned: %s\n", (char*)retval);
    free(retval);

}
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • In the compute function, do you mean "pthread_exit(ret)" or "return ret"? – Diogo Soares May 19 '19 at 09:30
  • 2
    @DiogoSoares `return`ing `ret` from the root function of a thread is equivalent to calling `pthread_exit(ret)`. You can call `pthred_exit(ret);` explicitly instead of `return`ing if you want to. It shouldn't change the result. – Petr Skocik May 19 '19 at 09:35