两个线程运行相同的io_service

时间:2019-07-28 01:32:26

标签: c++11 boost-asio

https://youtu.be/rwOv_tw2eA4?t=1030

此示例具有一个io_service和两个正在运行的线程。

  • io_service附加了两个任务:timer1和timer2

  • 创建了两个线程来运行io_service

void timer_expired( std:: string id )
{
    std::cout << timestamp() << ": " << id << ": begin\n";
    std::this_thread::sleep_for( std::chrono::seconds(3) );
    std::cout << timestamp() << ": " << id << ": end\n";
}

int main()
{
    boost::asio::io_service io_service;

    boost::asio::deadline_timer timer1( io_service, boost::posix_time::seconds(5) );
    boost::asio::deadline_timer timer2( io_service, boost::posix_time::seconds(5) );

    timer1.async_wait( []( auto ... ){ timer_expired("timer1"); });
    timer2.async_wait( []( auto ... ){ timer_expired("timer2"); });


    std::cout << timestamp() << ": calling io_service run\n";

    std::thread thread1( [&](){ io_service.run(); } );
    std::thread thread2( [&](){ io_service.run(); } );

    thread1.join();
    thread2.join();

    std::cout << timestamp() << ": done\n";

    return 0;
}

每次运行此示例时,输出看起来都不错,因为:

  • 两个计时器同时启动

  • 两个计时器同时到期(5秒后,它们是异步的)

  • 回调是在同一时间(3秒后)被调用的

作者指出,此代码中存在种族,应该不起作用(车库输出)。

不太清楚的是,我们有两个线程,每个线程可以服务一个完成处理程序(此处为计时器回调)。那为什么要比赛呢?而且我多次运行此代码,并且无法像作者所介绍的那样产生任何垃圾输出。

输出看起来像预期的一样,这是一个示例:

2019-07-28 11:27:44: calling io_service run
2019-07-28 11:27:49: timer1: begin
2019-07-28 11:27:49: timer2: begin
2019-07-28 11:27:52: timer1: end
2019-07-28 11:27:52: timer2: end
2019-07-28 11:27:52: done

1 个答案:

答案 0 :(得分:1)

处理程序在io_service::run中调用。您在io.run()工作的地方启动了两个线程。因此,您同时拥有两个runnig方法timer_expired。比赛是在访问cout流的同时进行的。

您很幸运看到如此出色的输出,但是当您在timer_expired中添加更多作品时:

void timer_expired( std:: string id )
{
    std::cout << timestamp() << ": " << id << ": begin\n";
    std::this_thread::sleep_for( std::chrono::seconds(3) );
    // ADD MORE LINES TO BE PRINTED
    for (int i = 0; i < 1000; ++i)
        std::cout << timestamp() << ": " << id << ": end" << std::endl;
}

您将看到交错的字符。

许多线程cout对象的访问不会导致崩溃(根据reference),

  

并发访问同步([ios.members.static])标准   iostream对象的格式化和未格式化输入和输出功能   或多线程的标准C流不应导致数据   种族。 [注意:用户仍必须同步同时使用这些   如果它们希望避免多个线程的对象和流   交错字符。

但是要避免这些交错的字符,您必须在访问cout时添加同步,例如通过使用std::mutex或以串行方式调用处理程序-使用boost中的strand对象。