網站首頁 編程語言 正文
一、并行編程
以下庫支持并行編程模型。
- Boost.Thread 允許您創建和管理自己的線程。
- Boost.Atomic 允許您通過多個線程的原子操作訪問整數類型的變量。
- Boost.Lockfree 提供線程安全的容器。
- Boost.MPI 起源于超級計算機領域。使用 Boost.MPI,您的程序可以多次啟動并在多個進程中執行。您專注于對應該并發執行的實際任務進行編程,而 Boost.MPI 會協調這些過程。使用 Boost.MPI,您無需處理諸如同步訪問共享數據之類的細節。但是,Boost.MPI 確實需要適當的運行時環境。
二、生成何管理Threads
????????這個庫中最重要的類是 boost::thread,它在 boost/thread.hpp 中定義。此類用于創建新線程。示例 44.1 是一個創建線程的簡單示例。
????????例 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();
}
????????新線程應該執行的函數的名稱被傳遞給 boost::thread 的構造函數。一旦示例 44.1 中的變量 t 被創建,函數 thread() 立即開始在它自己的線程中執行。此時,thread() 與 main() 函數同時執行。
????????為了防止程序終止,在新創建的線程上調用 join()。 join() 阻塞當前線程,直到為其調用 join() 的線程終止。這會導致 main() 等待直到 thread() 返回。
????????可以使用變量訪問特定線程 - 在本示例中為 t t - 以等待其終止。但是,即使 t 超出范圍并被銷毀,線程仍將繼續執行。線程一開始總是綁定到 boost::thread 類型的變量,但一旦創建,線程就不再依賴于該變量。甚至還有一個名為 detach() 的成員函數,它允許類型為 boost::thread 的變量與其對應的線程分離。不可能在調用 detach() 之后調用像 join() 這樣的成員函數,因為分離的變量不再代表有效的線程。
????????任何可以在函數內完成的事情也可以在線程內完成。歸根結底,線程與函數沒有什么不同,只是它與另一個函數并發執行。在例 44.1 中,循環中將五個數字寫入標準輸出流。為了減慢輸出速度,循環的每次迭代都會調用 wait() 函數來暫停一秒鐘。 wait() 使用函數 sleep_for() ,它也由 Boost.Thread 提供并位于命名空間 boost::this_thread 中。
????????sleep_for() 需要一個時間段作為其唯一參數,該時間段指示當前線程應該停止多長時間。通過傳遞類型為 boost::chrono::seconds 的對象,可以設置一段時間。 boost::chrono::seconds 來自第 37 章介紹的 Boost.Chrono。
????????sleep_for() 只接受來自 Boost.Chrono 的類型。盡管 Boost.Chrono 已成為 C++11 標準庫的一部分,但來自 std::chrono 的類型不能與 Boost.Thread 一起使用。這樣做會導致編譯器錯誤。
????????如果您不想在 main() 結束時調用 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 的構造函數需要一個 boost::thread 類型的對象。在 boost::scoped_thread 的析構函數中,一個動作可以訪問該對象。默認情況下,boost::scoped_thread 使用在線程上調用 join() 的操作。因此,示例 44.2 的工作方式類似于示例 44.1。
????????您可以將用戶定義的操作作為模板參數傳遞。該操作必須是一個帶有運算符 operator() 的類,該運算符接受 boost::thread 類型的對象。 boost::scoped_thread 保證運算符將在析構函數中調用。
????????您只能在 Boost.Thread 中找到類 boost::scoped_thread。標準庫中沒有對應的。確保包含 boost::scoped_thread 的頭文件 boost/thread/scoped_thread.hpp。
????????示例 44.3 引入了中斷點,這使得中斷線程成為可能。中斷點僅由 Boost.Thread 支持,標準庫不支持。
????????示例 44.3。 boost::this_thread::sleep_for() 的中斷點
#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();
}
????????在線程對象上調用 interrupt() 會中斷相應的線程。在此上下文中,中斷意味著在線程中拋出類型為 boost::thread_interrupted 的異常。但是,這僅在線程到達中斷點時發生。
????????如果給定的線程不包含中斷點,則簡單地調用 interrupt() 不會有任何效果。每當線程到達中斷點時,它都會檢查是否已調用 interrupt()。如果它已被調用,將拋出 boost::thread_interrupted 類型的異常。
????????Boost.Thread 定義了一系列中斷點,例如 sleep_for() 函數。因為在示例 44.3 中 sleep_for() 被調用了五次,線程檢查了五次它是否被中斷。在對 sleep_for() 的調用之間,線程不能被中斷。
????????示例 44.3 沒有顯示五個數字,因為在 main() 中三秒后調用了 interrupt()。因此,相應的線程被中斷并拋出 boost::thread_interrupted 異常。即使捕獲處理程序為空,異常也會在線程內被正確捕獲。因為 thread() 函數在處理程序之后返回,所以線程也會終止。反過來,這將導致程序終止,因為 main() 正在等待線程終止。
????????Boost.Thread 定義了大約十五個中斷點,包括 sleep_for()。這些中斷點使得及時中斷線程變得容易。然而,中斷點可能并不總是最好的選擇,因為它們必須在線程可以檢查 boost::thread_interrupted 異常之前到達。
????????示例 44.4。使用 disable_interruption 禁用中斷點
#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 防止線程被中斷。如果實例化 boost::this_thread::disable_interruption,只要對象存在,線程中的中斷點就會被禁用。因此,示例 44.4 顯示了五個數字,因為中斷線程的嘗試被忽略了。
????????示例 44.5。使用 boost::thread::attributes 設置線程屬性
#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 用于設置線程屬性。在 1.56.0 版本中,您只能設置一個與平臺無關的屬性,即堆棧大小。在示例 44.5 中,堆棧大小由 boost::thread::attributes::set_stack_size() 設置為 1024 字節。
示例 44.6。檢測線程 ID 和可用處理器的數量
#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 中,定義了適用于當前線程的獨立函數。其中一個函數是我們之前見過的 sleep_for()。另一個是 get_id(),它返回一個數字以唯一標識當前線程(參見示例 44.6)。 get_id() 也作為類 boost::thread 的成員函數提供。
????????靜態成員函數 boost::thread::hardware_concurrency() 返回物理上可以同時執行的線程數,基于 CPU 或 CPU 內核的基礎數量。在雙核處理器上調用此函數返回值 2。此函數提供了一種簡單的方法來確定理論上應該使用的最大線程數。
????????Boost.Thread 還提供類 boost::thread_group 來管理組中的線程。此類提供的一個函數是成員函數 join_all(),它等待組中的所有線程終止。
練習
使用兩個線程計算在 for 循環中相加的所有數字的總和:
#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';
}
概括該程序,使其使用盡可能多的線程,可以在計算機上并發執行。例如,如果程序在具有四核 CPU 的計算機上運行,??則該程序應該使用四個線程。
原文鏈接:https://yamagota.blog.csdn.net/article/details/127832756
相關推薦
- 2022-07-02 element-ui及時清除驗證規則
- 2023-03-22 go?install和go?get的區別實例詳解_Golang
- 2023-07-04 Linux之top命令詳解
- 2023-03-28 python如何實現向上取整_python
- 2022-10-07 Qt入門學習之數據庫操作指南_C 語言
- 2022-07-18 C語言枚舉類型
- 2022-05-05 基于PyQt5制作數據處理小工具_python
- 2023-01-05 Go語音開發中常見Error類型處理示例詳解_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支