Search code examples
c++multithreadingc++11shared-ptrfunctor

Passing a std::shared_ptr to a function object to std::thread


Need to have this Functor live as long as my thread does, so I've created a shared_ptr to it and trying to pass it to std::thread. I've copied the code and list of errors here.

struct Functor
{
    std::string greeting;
    explicit Functor(std::string _greeting="Hello!"): greeting { _greeting }     {}
    void operator()()
    {
        std::cout << greeting << "\n";
    }
};

auto main() ->int 
{
    std::shared_ptr<Functor> fp = std::make_shared<Functor> ();
    std::thread t(&fp);
    t.join();
    return 0;
}

List of errors:

Error   C2893   Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'    std_threads C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thr\xthread  240 
Error   C2672   'std::invoke': no matching overloaded function found    std_threads C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thr\xthread  240 

I'm new to c++11 and concurrency. Please help me understand the following

1>does a std::thread always invoke the operator() inside an object when passed by value ? If so, why it has been defined so.

2>how to ensure that a resource given to a thread stays around as long as the thread does?

3>is the Functor written here, a function object ?

4>What have I done here in this code ?!


Solution

  • 1>does a std::thread always invoke the operator() inside an object when passed by value ? If so, why it has been defined so.

    std::thread invokes std::invoke. From cppreference, if the first argument is neither a pointer to member function nor a pointer to data member; it is treated as a function object. So, fp() will be called.

    INVOKE(f, t1, t2, ..., tN) is equivalent to f(t1, t2, ..., tN) (that is, f is a FunctionObject)

    So you can basically do std::thread t{*fp}

    2>how to ensure that a resource given to a thread stays around as long as the thread does?

    You can have shared_ptr to provide ownership of a shared object. Or you can just manually do it by ensuring the resource passed is in scope. The mileage varies.

    3>is the Functor written here, a function object ?

    Yes. A FunctionObject type is the type of an object that can be used on the left of the function call operator. However fp is not. But *fp is.

    4>What have I done here in this code ?!

    You can make it work by explicitly passing Functor::operator() with argument fp.get(). Ofcourse a simple way is to just pass *fp

    Demo