C++ Boost Thread線程使用示例詳解
一、并行編程
以下庫支持并行編程模型。
- Boost.Thread 允許您創(chuàng)建和管理自己的線程。
- Boost.Atomic 允許您通過多個(gè)線程的原子操作訪問整數(shù)類型的變量。
- Boost.Lockfree 提供線程安全的容器。
- Boost.MPI 起源于超級(jí)計(jì)算機(jī)領(lǐng)域。使用 Boost.MPI,您的程序可以多次啟動(dòng)并在多個(gè)進(jìn)程中執(zhí)行。您專注于對(duì)應(yīng)該并發(fā)執(zhí)行的實(shí)際任務(wù)進(jìn)行編程,而 Boost.MPI 會(huì)協(xié)調(diào)這些過程。使用 Boost.MPI,您無需處理諸如同步訪問共享數(shù)據(jù)之類的細(xì)節(jié)。但是,Boost.MPI 確實(shí)需要適當(dāng)?shù)倪\(yùn)行時(shí)環(huán)境。
二、生成何管理Threads
這個(gè)庫中最重要的類是 boost::thread,它在 boost/thread.hpp 中定義。此類用于創(chuàng)建新線程。示例 44.1 是一個(gè)創(chuàng)建線程的簡(jiǎn)單示例。
例 44.1。使用 boost::thread
#include <boost/thread.hpp> #include <boost/chrono.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep_for(boost::chrono::seconds{seconds}); } void thread() { for (int i = 0; i < 5; ++i) { wait(1); std::cout << i << '\n'; } } int main() { boost::thread t{thread}; t.join(); }
新線程應(yīng)該執(zhí)行的函數(shù)的名稱被傳遞給 boost::thread 的構(gòu)造函數(shù)。一旦示例 44.1 中的變量 t 被創(chuàng)建,函數(shù) thread() 立即開始在它自己的線程中執(zhí)行。此時(shí),thread() 與 main() 函數(shù)同時(shí)執(zhí)行。
為了防止程序終止,在新創(chuàng)建的線程上調(diào)用 join()。 join() 阻塞當(dāng)前線程,直到為其調(diào)用 join() 的線程終止。這會(huì)導(dǎo)致 main() 等待直到 thread() 返回。
可以使用變量訪問特定線程 - 在本示例中為 t t - 以等待其終止。但是,即使 t 超出范圍并被銷毀,線程仍將繼續(xù)執(zhí)行。線程一開始總是綁定到 boost::thread 類型的變量,但一旦創(chuàng)建,線程就不再依賴于該變量。甚至還有一個(gè)名為 detach() 的成員函數(shù),它允許類型為 boost::thread 的變量與其對(duì)應(yīng)的線程分離。不可能在調(diào)用 detach() 之后調(diào)用像 join() 這樣的成員函數(shù),因?yàn)榉蛛x的變量不再代表有效的線程。
任何可以在函數(shù)內(nèi)完成的事情也可以在線程內(nèi)完成。歸根結(jié)底,線程與函數(shù)沒有什么不同,只是它與另一個(gè)函數(shù)并發(fā)執(zhí)行。在例 44.1 中,循環(huán)中將五個(gè)數(shù)字寫入標(biāo)準(zhǔn)輸出流。為了減慢輸出速度,循環(huán)的每次迭代都會(huì)調(diào)用 wait() 函數(shù)來暫停一秒鐘。 wait() 使用函數(shù) sleep_for() ,它也由 Boost.Thread 提供并位于命名空間 boost::this_thread 中。
sleep_for() 需要一個(gè)時(shí)間段作為其唯一參數(shù),該時(shí)間段指示當(dāng)前線程應(yīng)該停止多長(zhǎng)時(shí)間。通過傳遞類型為 boost::chrono::seconds 的對(duì)象,可以設(shè)置一段時(shí)間。 boost::chrono::seconds 來自第 37 章介紹的 Boost.Chrono。
sleep_for() 只接受來自 Boost.Chrono 的類型。盡管 Boost.Chrono 已成為 C++11 標(biāo)準(zhǔn)庫的一部分,但來自 std::chrono 的類型不能與 Boost.Thread 一起使用。這樣做會(huì)導(dǎo)致編譯器錯(cuò)誤。
如果您不想在 main() 結(jié)束時(shí)調(diào)用 join(),您可以使用類 boost::scoped_thread。
示例 44.2。使用 boost::scoped_thread 等待線程
#include <boost/thread.hpp> #include <boost/thread/scoped_thread.hpp> #include <boost/chrono.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep_for(boost::chrono::seconds{seconds}); } void thread() { for (int i = 0; i < 5; ++i) { wait(1); std::cout << i << '\n'; } } int main() { boost::scoped_thread<> t{boost::thread{thread}}; }
boost::scoped_thread 的構(gòu)造函數(shù)需要一個(gè) boost::thread 類型的對(duì)象。在 boost::scoped_thread 的析構(gòu)函數(shù)中,一個(gè)動(dòng)作可以訪問該對(duì)象。默認(rèn)情況下,boost::scoped_thread 使用在線程上調(diào)用 join() 的操作。因此,示例 44.2 的工作方式類似于示例 44.1。
您可以將用戶定義的操作作為模板參數(shù)傳遞。該操作必須是一個(gè)帶有運(yùn)算符 operator() 的類,該運(yùn)算符接受 boost::thread 類型的對(duì)象。 boost::scoped_thread 保證運(yùn)算符將在析構(gòu)函數(shù)中調(diào)用。
您只能在 Boost.Thread 中找到類 boost::scoped_thread。標(biāo)準(zhǔn)庫中沒有對(duì)應(yīng)的。確保包含 boost::scoped_thread 的頭文件 boost/thread/scoped_thread.hpp。
示例 44.3 引入了中斷點(diǎn),這使得中斷線程成為可能。中斷點(diǎn)僅由 Boost.Thread 支持,標(biāo)準(zhǔn)庫不支持。
示例 44.3。 boost::this_thread::sleep_for() 的中斷點(diǎn)
#include <boost/thread.hpp> #include <boost/chrono.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep_for(boost::chrono::seconds{seconds}); } void thread() { try { for (int i = 0; i < 5; ++i) { wait(1); std::cout << i << '\n'; } } catch (boost::thread_interrupted&) {} } int main() { boost::thread t{thread}; wait(3); t.interrupt(); t.join(); }
在線程對(duì)象上調(diào)用 interrupt() 會(huì)中斷相應(yīng)的線程。在此上下文中,中斷意味著在線程中拋出類型為 boost::thread_interrupted 的異常。但是,這僅在線程到達(dá)中斷點(diǎn)時(shí)發(fā)生。
如果給定的線程不包含中斷點(diǎn),則簡(jiǎn)單地調(diào)用 interrupt() 不會(huì)有任何效果。每當(dāng)線程到達(dá)中斷點(diǎn)時(shí),它都會(huì)檢查是否已調(diào)用 interrupt()。如果它已被調(diào)用,將拋出 boost::thread_interrupted 類型的異常。
Boost.Thread 定義了一系列中斷點(diǎn),例如 sleep_for() 函數(shù)。因?yàn)樵谑纠?44.3 中 sleep_for() 被調(diào)用了五次,線程檢查了五次它是否被中斷。在對(duì) sleep_for() 的調(diào)用之間,線程不能被中斷。
示例 44.3 沒有顯示五個(gè)數(shù)字,因?yàn)樵?main() 中三秒后調(diào)用了 interrupt()。因此,相應(yīng)的線程被中斷并拋出 boost::thread_interrupted 異常。即使捕獲處理程序?yàn)榭?,異常也?huì)在線程內(nèi)被正確捕獲。因?yàn)?thread() 函數(shù)在處理程序之后返回,所以線程也會(huì)終止。反過來,這將導(dǎo)致程序終止,因?yàn)?main() 正在等待線程終止。
Boost.Thread 定義了大約十五個(gè)中斷點(diǎn),包括 sleep_for()。這些中斷點(diǎn)使得及時(shí)中斷線程變得容易。然而,中斷點(diǎn)可能并不總是最好的選擇,因?yàn)樗鼈儽仨氃诰€程可以檢查 boost::thread_interrupted 異常之前到達(dá)。
示例 44.4。使用 disable_interruption 禁用中斷點(diǎn)
#include <boost/thread.hpp> #include <boost/chrono.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep_for(boost::chrono::seconds{seconds}); } void thread() { boost::this_thread::disable_interruption no_interruption; try { for (int i = 0; i < 5; ++i) { wait(1); std::cout << i << '\n'; } } catch (boost::thread_interrupted&) {} } int main() { boost::thread t{thread}; wait(3); t.interrupt(); t.join(); }
類 boost::this_thread::disable_interruption 防止線程被中斷。如果實(shí)例化 boost::this_thread::disable_interruption,只要對(duì)象存在,線程中的中斷點(diǎn)就會(huì)被禁用。因此,示例 44.4 顯示了五個(gè)數(shù)字,因?yàn)橹袛嗑€程的嘗試被忽略了。
示例 44.5。使用 boost::thread::attributes 設(shè)置線程屬性
#include <boost/thread.hpp> #include <boost/chrono.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep_for(boost::chrono::seconds{seconds}); } void thread() { try { for (int i = 0; i < 5; ++i) { wait(1); std::cout << i << '\n'; } } catch (boost::thread_interrupted&) {} } int main() { boost::thread::attributes attrs; attrs.set_stack_size(1024); boost::thread t{attrs, thread}; t.join(); }
boost::thread::attributes 用于設(shè)置線程屬性。在 1.56.0 版本中,您只能設(shè)置一個(gè)與平臺(tái)無關(guān)的屬性,即堆棧大小。在示例 44.5 中,堆棧大小由 boost::thread::attributes::set_stack_size() 設(shè)置為 1024 字節(jié)。
示例 44.6。檢測(cè)線程 ID 和可用處理器的數(shù)量
#include <boost/thread.hpp> #include <iostream> int main() { std::cout << boost::this_thread::get_id() << '\n'; std::cout << boost::thread::hardware_concurrency() << '\n'; }
在命名空間 boost::this_thread 中,定義了適用于當(dāng)前線程的獨(dú)立函數(shù)。其中一個(gè)函數(shù)是我們之前見過的 sleep_for()。另一個(gè)是 get_id(),它返回一個(gè)數(shù)字以唯一標(biāo)識(shí)當(dāng)前線程(參見示例 44.6)。 get_id() 也作為類 boost::thread 的成員函數(shù)提供。
靜態(tài)成員函數(shù) boost::thread::hardware_concurrency() 返回物理上可以同時(shí)執(zhí)行的線程數(shù),基于 CPU 或 CPU 內(nèi)核的基礎(chǔ)數(shù)量。在雙核處理器上調(diào)用此函數(shù)返回值 2。此函數(shù)提供了一種簡(jiǎn)單的方法來確定理論上應(yīng)該使用的最大線程數(shù)。
Boost.Thread 還提供類 boost::thread_group 來管理組中的線程。此類提供的一個(gè)函數(shù)是成員函數(shù) join_all(),它等待組中的所有線程終止。
練習(xí)
使用兩個(gè)線程計(jì)算在 for 循環(huán)中相加的所有數(shù)字的總和:
#include <boost/timer/timer.hpp> #include <iostream> #include <cstdint> int main() { boost::timer::cpu_timer timer; std::uint64_t total = 0; for (int i = 0; i < 1'000'000'000; ++i) total += i; std::cout << timer.format(); std::cout << total << '\n'; }
概括該程序,使其使用盡可能多的線程,可以在計(jì)算機(jī)上并發(fā)執(zhí)行。例如,如果程序在具有四核 CPU 的計(jì)算機(jī)上運(yùn)行,??則該程序應(yīng)該使用四個(gè)線程。
到此這篇關(guān)于C++ Boost Thread線程使用示例詳解的文章就介紹到這了,更多相關(guān)C++ Boost Thread內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言深入淺出講解直接插入排序算法的實(shí)現(xiàn)
插入排序也是最簡(jiǎn)單的一類排序方法,我今天介紹的也是插入排序里最直觀且淺顯易懂的直接插入排序。對(duì)這個(gè)很簡(jiǎn)單的排序,記得當(dāng)時(shí)也是花了近兩個(gè)晚上才搞懂它的原理的,接下來就來介紹一下2022-05-05C/C++?Qt?StatusBar底部狀態(tài)欄應(yīng)用教程
Qt窗體中默認(rèn)會(huì)附加一個(gè)QstatusBar組件,狀態(tài)欄組件位于主窗體的最下方,其作用是提供一個(gè)工具提示功能。本文主要介紹了StatusBar底部狀態(tài)欄的應(yīng)用教程,需要的同學(xué)可以學(xué)習(xí)一下2021-12-12關(guān)于C/C++中typedef的定義與用法總結(jié)
在C還是C++代碼中,typedef都使用的很多,在C代碼中尤其是多,typedef與#define有些相似,其實(shí)是不同的,特別是在一些復(fù)雜的用法上,需要的朋友可以參考下2012-12-12