【问题标题】:What is the advantage of strand in boost asio?strand 在 boost asio 中的优势是什么?
【发布时间】:2014-10-11 09:44:51
【问题描述】:

据我了解,学习 boost asio 并找出一个名为“strand”的类。 如果只有一个 io_service 关联到特定 strand 并按 strand 发布句柄。

示例(来自here

boost::shared_ptr< boost::asio::io_service > io_service( 
    new boost::asio::io_service
);
boost::shared_ptr< boost::asio::io_service::work > work(
    new boost::asio::io_service::work( *io_service )
);
boost::asio::io_service::strand strand( *io_service );

boost::thread_group worker_threads;
for( int x = 0; x < 2; ++x )
{
    worker_threads.create_thread( boost::bind( &WorkerThread, io_service ) );
}

boost::this_thread::sleep( boost::posix_time::milliseconds( 1000 ) );

strand.post( boost::bind( &PrintNum, 1 ) );
strand.post( boost::bind( &PrintNum, 2 ) );
strand.post( boost::bind( &PrintNum, 3 ) );
strand.post( boost::bind( &PrintNum, 4 ) );
strand.post( boost::bind( &PrintNum, 5 ) );

然后 strand 将为我们序列化处理程序执行。但是这样做有什么好处呢?如果我们希望任务变为序列化?

【问题讨论】:

    标签: c++ boost boost-asio


    【解决方案1】:

    想象一个系统,其中单个io_service 管理数百个网络连接的套接字。为了能够并行化工作负载,系统维护了一个调用 io_service::run 的工作线程池。

    现在这种系统中的大部分操作都可以并行运行。但有些必须被序列化。例如,您可能不希望在同一个套接字上同时发生多个写操作。然后,您将使用每个套接字的一个链来同步写入:不同套接字上的写入仍然可以同时发生,而对相同套接字的写入将被序列化。工作线程不必关心同步或不同的套接字,它们只需抓住io_service::run 提供的任何东西。

    有人可能会问:为什么我们不能只使用互斥锁来代替同步呢? strand 的优点是,如果 strand 已经在工作,则不会首先安排工作线程。使用互斥体,工作线程会收到回调,然后会阻塞锁定尝试,阻止线程做任何有用的工作,直到互斥体可用。

    【讨论】:

    • 我知道这个问题已经过时了,但我想提一下一篇博文,剖析了对股的看法 (crazygaze.com/blog/2016/03/17/…)。免责声明:我是作者。
    【解决方案2】:

    我知道它太旧了,但希望它能帮助新用户通过示例来理解。读取代码中的cmets

    #define BOOST_DATE_TIME_NO_LIB
    #define BOOST_REGEX_NO_LIB
    
    #include <boost/asio.hpp>
    #include <boost/shared_ptr.hpp>
    #include <boost/thread.hpp>
    #include <boost/thread/mutex.hpp>
    #include <boost/bind.hpp>
    #include <iostream>
    
    boost::mutex global_stream_lock;
    
    void WorkerThread(boost::shared_ptr<boost::asio::io_service> iosvc, int counter) {
        global_stream_lock.lock();
        std::cout << "Thread " << std::this_thread::get_id() << ", " << counter << " Start.\n";
        global_stream_lock.unlock();
    
        iosvc->run();
    
        global_stream_lock.lock();
        std::cout << "Thread " << counter << " End.\n";
        global_stream_lock.unlock();
    }
    
    void async_send_handler(int number) {
        std::cout << "Number: " << number << ", threadID: " << std::this_thread::get_id() << std::endl;
    }
    
    int main(void) {
        boost::shared_ptr<boost::asio::io_service> io_svc(
            new boost::asio::io_service
        );
    
        boost::shared_ptr<boost::asio::io_service::work> worker(
            new boost::asio::io_service::work(*io_svc)
        );
    
        boost::asio::io_service::strand strand(*io_svc);
    
        global_stream_lock.lock();
        std::cout << "The program will exit once all work has finished.\n";
        global_stream_lock.unlock();
    
        boost::thread_group threads;
        for( int i = 1; i <= 5; i++ )
            threads.create_thread(boost::bind(&WorkerThread, io_svc, i));
    
        boost::this_thread::sleep(boost::posix_time::milliseconds(500));
    
        // Imagine you are invoking async_send on tcp or udp socket several times
        // and you want the handlers of this async_send call to be invoked sequentially
    
        // This code is almost equal to calling handlers of socket.async_send.
        // The handlers are invoked concurently and the order might be arbitrary
        io_svc->post(boost::bind(&async_send_handler, 1));
        io_svc->post(boost::bind(&async_send_handler, 2));
        io_svc->post(boost::bind(&async_send_handler, 3));
        io_svc->post(boost::bind(&async_send_handler, 4));
        io_svc->post(boost::bind(&async_send_handler, 5));
    
        // This code will do what you exactly want;
        // It will execute the handlers sequentially in that order
        strand.post(boost::bind(&async_send_handler, 1));
        strand.post(boost::bind(&async_send_handler, 2));
        strand.post(boost::bind(&async_send_handler, 3));
        strand.post(boost::bind(&async_send_handler, 4));
        strand.post(boost::bind(&async_send_handler, 5));
    
        worker.reset();
    
        threads.join_all();
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-29
      相关资源
      最近更新 更多