Search code examples
c++pthreadsshared-ptr

C++11 shared_ptr and pthread


I have a library with APIs using std::shared_ptr as arguments.

I would like to use these APIs together with pthreads.

What I'm doing is: getting a raw pointer from the shared_ptr, in order to pass it to the pthread. Create a new shared_ptr from the raw one and call my API from another thread. However I get a double free or corruption error when converting the raw pointer back to a shared one.

This is my code

#include <memory>
#include <iostream>
#include <thread>
#include <pthread.h>

void* print_task(void* ptr) 
{
    int* val_raw = static_cast<int*>(ptr);
    std::shared_ptr<int> val(val_raw);

    // CALL MY API WHICH TAKES A SHARED_PTR AS ARGUMENT
    std::cout<<"thread job done \n";
}

int main(int argc, char ** argv)
{

   pthread_t thread;

   std::shared_ptr<int> val = std::make_shared<int>(10);
   pthread_create(&thread, nullptr, &print_task, static_cast<void *>(val.get()));

   std::this_thread::sleep_for(std::chrono::seconds(5));

   return 0;
}

I guess that I'm doing something wrong with all the conversions from shared to raw pointer, because the same code using std::threads (where I can pass directly a shared_ptr) works. However I need to set thread priorities, thus I'm trying to do this with pthreads.

Do you know how to change my code in order to be able to pass a shared pointer and use it inside a pthread?


Solution

  • As mentioned in the comments already, the problem is passing a shared pointer through a raw void pointer, so I'll ignore the threading part for now:

    // this is what we have and what we want to pass to the given function
    shared_ptr<some_type> sptr;
    
    // function to somehow pass the shared pointer to
    void function(void* ptr);
    
    // As always, when passing anything that doesn't fit into
    // the raw pointer, we need to do dynamic allocation:
    void* arg = new shared_ptr<some_type>(sptr);
    
    // we can now pass this to the function as intended:
    function(arg);
    
    // Note that we give up ownership of the dynamically allocated
    // shared pointer instance. Hence, the called function must
    // release that object again (it takes ownership). The function
    // therefore starts like this:
    void function(void* ptr)
    {
        // convert the typeless pointer to a typed pointer again
        shared_ptr<some_type>* psptr = static_cast<shared_ptr<some_type>*>(ptr);
        // move the content to a new, local instance
        shared_ptr<some_type> sptr = *psptr;
        // release the dynamically allocated shared pointer again
        delete psptr;
        /// ... code using sptr here ...
    }
    

    Now, while this is guaranteed to work, under some circumstances this may not be an optimal solution:

    • Firstly, the ups and downs of the reference counter don't come for free, especially since that is done in a thread-safe, atomic way. Copying the shared pointer inside the function just to then delete the copied pointer can be avoided. Just create as empty instance and swap() it with the pointer to copy. Assuming swap() is specialized, which is a safe bet because it's an obvious optimization, that then boils down to swapping two raw pointers. This swap doesn't have to be thread-safe and is therefore much faster.
    • Secondly, dynamic allocations are expensive. You could avoid this and the manual release by passing the address of the original object to the function, but then you would have to guarantee that the object is not touched while the function is still executing. Especially with threads, that requires taking extra care.