繁体   English   中英

在boost asio中strand有什么优势?

[英]What is the advantage of strand in boost asio?

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

例子(从这里

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 将为我们序列化处理程序的执行。但是这样做有什么好处?如果我们希望任务序列化,为什么不创建一个单独的线程(例如:在 for 循环中使 x = 1)?

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

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

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

我知道它太旧了,但希望它可以通过示例帮助新用户理解。 阅读代码中的注释

#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;
}

看起来很奇怪 - 细粒度锁定不是更可取吗? 在相当大的函数上使用一个链,其中的主要部分不需要锁定,最终会序列化整个函数 - 当只有小部分需要锁定时。 我想这不是一个硬性规定——你必须看看情况,看看链是否有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM