Returning void pointer in pthread

1k Views Asked by At

I just started learning multi-threading in C++ with pthreads. I am working with the following code:

struct ArgT{
    int a;
    int b;

    ArgT(int a, int b)
        : a(a), b(b)
    {}

    ArgT()
        :a(0), b(0)
    {}
};

void* worker(void* arg)
{
    ArgT* myArg = (ArgT*) arg;
    int* result = new int;

    *result = myArg->a + myArg->b;

    std::cout << "(void*)result: " << (void*) result << std::endl;
    return (void*)result;
}

int main()
{
    ArgT mainArg(2,3);
    pthread_t p;
    int* main_result;

    pthread_create(&p, NULL, worker, (void*)&mainArg);
    pthread_join(p, (void**)&main_result); //??

    std::cout << "main_result: " << main_result << std::endl; 
    std::cout << "&main_result: "<< &main_result << std::endl;
    printf("\nResult = %d\n", *main_result);

    delete main_result;

    return 0;
}

The output of the code is as follows

(void*)result: 0x7f07ac0008c0
main_result: 0x7f07ac0008c0
&main_result: 0x7fffb1aa0588

Result = 5

My question is pthread_join() accepts void** as second argument, which is basically address of an address. Whereas we are returning an address of type void* in the worker() function. How are these two types compatible?

2

There are 2 best solutions below

0
On

pthread_join() takes the address of a pointer variable. That variable will receive the pointer value that the thread returns. It is effectively doing the same as this:

void doIt(void (*f)(), void** ptr)
{
    *ptr = f();
}

void* func()
{
    return ...; 
}

int main()
{
    void *ptr;
    doIt(func, &ptr);
    // ptr holds whatever func() returns...
}
2
On

How are these two types compatible?

When void** is indirected through, the result is lvalue of type void*


Your program has undefined behaviour. Here is a correct way:

void* void_main_result;

pthread_join(p, &void_main_result);

int* int_main_result = static_cast<int*>(void_main_result);
std::cout << "\nResult = " << *int_main_result;

You can avoid dynamic allocation by allocating the result within the arguments. That way the return value isn't needed:

struct ArgRet {
    ArgT args;
    int ret;
} mainArg;

pthread_create(&p, NULL, worker, &mainArg);

std::cout << "\nResult = " << mainArg.ret;

// in worker
ArgRet* myArg = static_cast<ArgRet*>(arg);
myArg->ret = myArg->args.a + myArg->args.b;
return arg; // or nullptr; doesn't really matter

what's the main advantage of using std::thread instead of pthreads

std::thread works in all C++ (11 or later) implementations. pthreads only work on POSIX systems. The API of std::thread is also easier to use since it is written in C++ rather than C.


P.S. Converting a pointer to void* is implicit. I recommend not using C-style casts.