探究boost::asio::io_service

一、基本介紹

boost::asio::io_service是boost庫中實現異步編程的關鍵組件,它提供了一個事件循環機制,負責處理I/O操作、定時器、信號等事件,同時其多線程支持,可以在多個線程中並行執行任務,增強了程序的並發性。

boost::asio::io_service定義於asio庫的頭文件中,創建一個io_service對象通常使用默認的構造函數,沒有任何參數,如下所示:

boost::asio::io_service io_service;

當有I/O操作(如異步的讀寫socket)需要進行時,我們需要將該操作添加到io_service的隊列中,同時運行io_service,等待事件的發生,代碼如下:

io_service.run();

run()方法將會等待io_service中任何派生自boost::asio::io_service::work的對象被引用的引用計數變為0才會退出,也就是說,如果你希望asio庫一直工作,就要維護至少一個work對象。

二、工作模式

為了提高程序的性能、並發性,asio庫提供了許多多線程支持的類,例如io_service::work,io_service::strand。針對io_service對象,有兩種工作模式:

1、單線程模式

在單線程模式下,所有I/O事件都在一個線程中被處理,由於沒有線程切換的開銷,原生的單線程模式的性能是最好的。一般情況下,我們通常在主線程中創建io_service對象,並且沒有任何其他的線程參與,代碼如下:

boost::asio::io_service io_service;
//添加恆定的work對象,保證io_service一直工作
boost::asio::io_service::work work(io_service); 
io_service.run();

在這個例子中,我們在io_service的隊列中永遠存在一個work,所以io_service.run()會一直運行,直到該work被銷毀。

2、多線程模式

當有多個線程需要共享I/O操作,如異步socket讀寫時,我們可以在多個線程中同時運行io_service,代碼如下:

boost::asio::io_service io_service;
//添加恆定的work對象,保證io_service一直工作
boost::asio::io_service::work work(io_service);
//創建多個線程執行io_service的run方法
std::vector threads; 
for (std::size_t i = 0; i < num_threads; ++i)
{
    threads.emplace_back([&io_service]() {
        io_service.run();
    });
}
//等待所有線程執行完run方法後再退出
for (auto& t : threads)
{
    t.join();
}

在上述代碼中,我們先創建了一個io_service對象,並始終保持一個io_service::work對象,然後創建若干線程,每個線程都調用io_service的run()方法以處理I/O事件。最後,等待所有的線程完成run()方法後再退出。

三、io_service::strand(協程)

io_service::strand是另外一個很重要的類,它實現了線程安全的FIFO隊列,保證了在同一個strand對象中提交的所有handler被按照提交的先後順序依次執行(但保證不了跨strand對象的handler之間的順序)。這種技術和協程類似,又稱為“異步協程”。將io_service::strand應用於handler處理程序可以消除並發數據訪問所產生的數據競爭和死鎖,並且可以保證每個handler的獨立執行。

我們通過boost::asio::io_service::strand::wrap()創建一個新的handler,在strand對象中執行,如下代碼所示:

boost::asio::io_service::strand strand(io_service);
boost::asio::async_read(socket, buffer,
    strand.wrap([](const boost::system::error_code& ec,
                   std::size_t bytes_transferred) {
        //read完成的回調函數
    })
);

在上述代碼中,我們使用async_read方法讀取socket的數據,並且將回調函數封裝到strand執行,這樣就保證了回調的線程安全。

四、定時器(timer)

Asio庫中提供了定時器處理機制,這類工作放到io_service的隊列中,由io_service在指定時間觸髮指定handler。代碼如下所示:

boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(5));
timer.async_wait([&](const boost::system::error_code& error){
    if (!error) {
        //定時器超時後執行的操作
    }
});

在上述代碼中,我們創建了一個以秒為單位的定時器timer,並在該定時器超時指定時間後進行回調操作。

五、信號(signal)

Asio庫還提供了鬧鐘信號(signal)處理,使用方法與定時器類似,但是信號僅僅對UNIX系統起作用,Windows系統不支持。代碼如下所示:

boost::asio::signal_set signals(io_service, SIGINT, SIGTERM);
signals.async_wait([=](const boost::system::error_code& error,
                       int signal_number) {
    //處理信號
    if (!error) {
        io_service.stop();
    }
});

在上述代碼中,我們創建了一個信號集合,關注的信號包括SIGINT和SIGTERM,當這兩個信號被觸發時,程序會執行相關回調函數中的代碼。

六、總結

通過對boost::asio::io_service的多個方面的探究,我們了解了該組件實現異步編程的關鍵性,同時掌握了其多線程支持、協程、定時器、信號等特點。對於實現高效異步編程的應用程序,boost::asio::io_service是一個必須要了解和掌握的工具。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/154947.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-11-17 02:37
下一篇 2024-11-17 02:37

相關推薦

發表回復

登錄後才能評論