chriskohlhoff / asio

Asio C++ Library
http://think-async.com/Asio
4.72k stars 1.19k forks source link

Within win_iocp_io_context::shutdown() deadlock on GetQueuedCompletionStatus #1393

Open SunriseChen opened 6 months ago

SunriseChen commented 6 months ago

The following code causes GetQueuedCompletionStatus(...) within win_iocp_io_context::shutdown() to deadlock.

#include <gtest/gtest.h>
#include <boost/asio.hpp>

using namespace std;
using namespace boost::asio;

class AsioTimer
{
public:
    explicit AsioTimer(int value) : m_value(value), m_timer(m_context, 1ms), m_thread(&AsioTimer::run, this)
    {
        m_timer.async_wait(bind(&AsioTimer::timeout, this));
    }

    ~AsioTimer()
    {
        auto running = true;
        if (m_running.compare_exchange_strong(running, false))
        {
            if (m_timer.cancel() < 1)
            {
                cerr << "AsioTimer(" << m_value << ") timer cancel return 0" << endl;
            }

            m_context.stop();
            if (m_thread.joinable())
            {
                m_thread.join();
            }
        }
    }

private:
    void run()
    {
        while (m_running)
        {
            try
            {
                m_context.run();
            }
            catch (const exception &ex)
            {
                cerr << "run error: " << ex.what() << endl;
            }
        }
    }

    void timeout() { m_timer.async_wait(bind(&AsioTimer::timeout, this)); }

    int m_value = 0;
    io_context m_context;
    steady_timer m_timer;
    thread m_thread;
    atomic_bool m_running = true;
};

TEST(AsioTimerCancel, test)
{
    auto count = 10000;
    for (auto i = 0; i < count; ++i)
    {
        AsioTimer timer(i);
        this_thread::sleep_for(1ms);
    }
}