Search code examples
c++boostasio

asio::io_service::run doesnt return after boost::asio::io_service::work is destroyed


As title says I'm having this problem when I can't understand why this thread

enter image description here

never stops running even after Client's destructor destroys asio::io_service::work variable

enter image description here

When I'm running this program output is always like this

enter image description here

Anyone sees what I'm missing here?

#include <boost/asio.hpp>
#include <thread>
#include <atomic>
#include <memory>

using namespace boost;


class Client{
public:

    Client(const Client& other) = delete;

    Client()
    {
        m_work.reset(new boost::asio::io_service::work(m_ios));

        m_thread.reset(new std::thread([this]()
        {
            m_ios.run();
        }));
    }

    ~Client(){ close(); }

private:

    void close();

    asio::io_service m_ios;
    std::unique_ptr<boost::asio::io_service::work> m_work;
    std::unique_ptr<std::thread> m_thread;

};

void Client::close()
{
    m_work.reset(nullptr);

    if(m_thread->joinable())
    {
        std::cout << "before joining thread" << std::endl;
        m_thread->join();
        std::cout << "after joining thread" << std::endl;
    }
}



int main()
{
    {
         Client client;
    }

    return 0;
}

EDIT


After StPiere comments I changed code to this and it worked :)

class Client{
public:

    Client(const Client& other) = delete;

    Client()
    {
        m_work.reset(new boost::asio::executor_work_guard<boost::asio::io_context::executor_type>(boost::asio::make_work_guard(m_ios)));
        m_thread.reset(new std::thread([this]()
        {
            m_ios.run();
        }));
    }

    ~Client(){ close(); }

private:

    void close();

    asio::io_context m_ios;

    std::unique_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> m_work;
    std::unique_ptr<std::thread> m_thread;

};

Solution

  • I cannot reproduce the error on either compiler. Here example for gcc 9.3 and boost 1.73

    Normally the work destructor will use something like InterLockedDecrement on windows to decrement the number of outstanding works.

    It looks like some compiler or io_service/work implementation issue.

    As stated in comments, io_service and io_service::work are deprecated in terms of io_context and executor_work_guard.