Question

In my multi-threaded programs I often use an approach like shown below to synchronize access to data:

class MyAsyncClass
{

public:     // public thread safe interface of MyAsyncClass

    void start()
    {
        // add work to io_service
        _ioServiceWork.reset(new boost::asio::io_service::work(_ioService));

        // start io service
        _ioServiceThread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&boost::asio::io_service::run, &_ioService)));
    }

    void stop()
    {
        _ioService.post(boost::bind(&MyAsyncClass::stop_internal, this));

        // QUESTION:
        // how do I wait for stop_internal to finish here?

        // remove work
        _ioServiceWork.reset();

        // wait for the io_service to return from run()
        if (_ioServiceThread && _ioServiceThread->joinable())
            _ioServiceThread->join();

        // allow subsequent calls to run()
        _ioService.reset();

        // delete thread
        _ioServiceThread.reset();
    }

    void doSometing()
    {
        _ioService.post(boost::bind(&MyAsyncClass::doSometing_internal, this));
    }

private:        // internal handlers

    void stop_internal()
    {
        _myMember = 0;
    }

    void doSomething_internal()
    {
        _myMember++;
    }

private:        // private variables

    // io service and its thread
    boost::asio::io_service _ioService;
    boost::shared_ptr<boost::thread> _ioServiceThread;

    // work object to prevent io service from running out of work
    std::unique_ptr<boost::asio::io_service::work> _ioServiceWork;

    // some member that should be modified only from _ioServiceThread
    int _myMember;

};

The public interface of this class is thread-safe in the sense that its public methods can be called from any thread and boost::asio::io_service takes care that access to the private members of this class are synchronized. Therefore the public doSomething() does nothing but posting the actual work into the io_service.

The start() and stop() methods of MyAsyncClass obviously start and stop processing in MyAsyncClass. I want to be able to call MyAsyncClass::stop() from any thread and it should not return before the uninitialization of MyAsyncClass has finished.

Since in this particular case I need to modify one of my private members (that needs synchronized access) when stopping, I introduced a stop_internal() method which I post to the io_service from stop().

Now the question is: How can I wait for the execution of stop_internal() to finish inside stop()? Note that I cannot call stop_internal() directly because it would run in the wrong thread.

Edit:

It would be nice to have a solution that also works if MyAsyncClass::stop() is called from the _ioServiceThread, so that MyAsyncClass can also stop itself.

Was it helpful?

Solution

I just found a very nice solution myself:

Instead of removing work (resetting _ioServiceWork) in stop(), I do it at the end of stop_internal(). This means that _ioServiceThread->join() blocks until stop_internal() has finished - exactly what I want.

The nice thing about this solution is that it doesn't need any mutex or condition variable or stuff like this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top