1

I need to start a thread that calls a public member function of the class Foo while inside of a public function that belongs to the class Bar. How do I achieve this?

I have tried the following (made trivial):

void Bar::BarFunc()
{ 
    // Do some BarFunc stuff 

    // Start a thread that needs to do stuff independently of BarFunc
    std::thread t(&Foo::FooFunc, FooFunc params,..,.., ???);
    t.detach();

    return;
}

This is my first time dealing with threading and the actual problem is a little more complex - BarFunc is a virtual function of a State class, with n-concrete classes implementing the different states my application can exist in, hence the question. I am not sure what to put as the last parameter, if anything. I have looked at this answer but cannot discern which syntax to use, if any of them even apply.

Finally, if this is bad practice all together, I would be grateful for any design advice.

Community
  • 1
  • 1
  • 4
    Due to "This is my first time dealing with threading": Do not detach a thread! –  Jun 29 '16 at 21:36
  • @DieterLücking How would I go about properly using the join function? – network drift Jun 29 '16 at 21:38
  • The parameters required depend on `Foo::FooFunc`, to which we are unfortunately not privy. I fear you may have reduced your example a bit too much. If you have a stack of different classes with different possible arguments you may be able to make use of [std::bind](http://en.cppreference.com/w/cpp/utility/functional/bind), to pre-package the function with the arguments. – user4581301 Jun 29 '16 at 21:43
  • @user4581301 My apologies - circumstances require me to heavily trivialize. Thank you for the advice. `Foo::FooFunc` takes a reference to a `std::list` object. `Bar::BarFunc` takes no parameters. I'll give bind a look see. – network drift Jun 29 '16 at 21:48
  • Is it okay if your `Bar` class goes out of scope while your threads are running? Otherwise you'll need to hang onto those threads and at a minimum `.join()` them in your destructor. – AndyG Jun 29 '16 at 21:52
  • @AndyG Yes. `BarFunc` returns a call to the object's updated state's `BarFunc`. `FooFunc` affects a data structure that is not local to any state's `BarFunc`. I hope that makes sense. – network drift Jun 29 '16 at 22:01
  • You can check out lambda closures as an alternative to `bind`. In either case, pay careful attention to the lifetimes of the objects you're capturing. Also, you said "_Bar::BarFunc takes no parameters_", but unless `Bar::BarFunc` is declared `static`, it implicitly takes a parameter of `Bar*` (a `this` pointer to the object that the function was called on). – mkal Jun 29 '16 at 22:16

1 Answers1

1

You likely have to manage two instances:

  • An instance of Foo
  • A thread executing a member function of Foo

That leads to the following sketch of a class Bar:

#include <iostream>
#include <thread>

struct Foo{
    void print(std::string s) { // by value!
        std::cout << s;
    }
};

class Bar{
    public:
    void hello() {
        // Ensure the thread is not running 
        // (Only one thread is supported in this example)
        if( ! foo_thread.joinable()) {
            // Move a newly constructed thread to the class member.
            foo_thread = std::thread(
                &Foo::print,        // pointer to member function of Foo
                &foo,               // pointer to the instance of Foo
                "hello\n"           // arguments by value
            );
        }
    }

    ~Bar() {
        // Ensure the thread has been started.
        if(foo_thread.joinable()) {
            // This will block until the thread has finished.
            foo_thread.join();
        }
    }

    private:
    Foo foo;
    std::thread foo_thread;
};

int main()
{
    Bar bar;
    bar.hello();
}

Note: The thread is not detached. A detached (not maintained properly) running thread, will get killed at end of the program and resources used by that thread (e.g.: file handles) might not be returned to the system.

  • Thank you. This helped me see a better way to implement the thread: the object only needs to exist during the thread's lifetime. I'll instantiate the object and join the thread by destroying the object. – network drift Jun 30 '16 at 15:40