安全地中断C ++ 11阻塞操作

时间:2016-02-08 09:36:33

标签: c++ multithreading c++11 boost condition-variable

我有一个std::thread使用Boost的asio从串口读取:

std::atomic<bool> quit(false);

void serialThread()
{
    try
    {
        asio::io_service io;
        asio::serial_port port(io);

        port.open("COM9"); // Yeay no port enumeration support!

        port.set_option(asio::serial_port_base::baud_rate(9600));

        while (!quit)
        {
            asio::streambuf buf;
            asio::read_until(port, buf, "\n");

            auto it = asio::buffers_begin(buf.data());
            string line(it, it + buf.size());

            doStuffWithLine(line);
        }
    }
    catch (std::exception e)
    {
        cout << "Serial thread error: " << e.what() << endl;
    }
}

void SetupSignals()
{
    // Arrange it so that `quit = true;` happens when Ctrl-C is pressed.
}

int main(int argc, char *argv[])
{
    SetupSignals();

    thread st(serialThread);

    st.join();

    return 0;
}

当我按下Ctrl-C时,我希望 干净地 退出该线程,以便正确调用所有析构函数(Windows上的某些驱动程序如果你不喜欢它就会讨厌它#39 ; t正确关闭他们的资源。)

不幸的是,正如您所看到的,read_until()中的当前代码阻塞,因此当您按下Ctrl-C时,在收到新的文本行之前不会发生任何事情。

一种解决方案是使用轮询,如下所示:

asio::async_read_until(port, buf, "\n", ...);
while (!quit)
    io.poll();

但我不想使用民意调查。它非常不优雅。我目前可以看到的唯一解决方案是在std::condition_variable quitOrIoFinished设置为true或者读取完成时触发quit。但是我没有写asio所以我不能给它一个条件变量来等待。

有没有清洁的理智解决方案?在Go中,我只使用select在多个频道上等待,其中一个频道是退出频道。我不能在C ++中看到类似的解决方案。

1 个答案:

答案 0 :(得分:1)

使用asio::signal_set等待INT信号(control-C倾向于发送中断)。

当它到达时,只需使用挂起的异步操作在IO对象上调用cancel()即可。他们将返回时error_code等于boost::asio::error::operation_aborted

现在,如果您有一个io_service::work对象,请对其进行破坏,并返回运行io_service::run()的所有线程,以便您可以加入它们。

注意注意同步对IO对象的访问(例如,当您对它们调用cancel()时)因为这些对象不是线程安全的,不像io_service和{ {1}}。