一、基本介紹
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