網站首頁 編程語言 正文
Boost.Lockfree
一、說明
Boost.Lockfree 提供線程安全和無鎖容器??梢詮亩鄠€線程訪問此庫中的容器,而無需同步訪問。
在 1.56.0 版本中,Boost.Lockfree 只提供了兩個容器:boost::lockfree::queue 類型的隊列和 boost::lockfree::stack 類型的棧。對于隊列,可以使用第二個實現:boost::lockfree::spsc_queue。此類針對只有一個線程寫入隊列和只有一個線程從隊列讀取的用例進行了優化。類名中的縮寫 spsc 代表單一生產者/單一消費者。
二、示例和代碼
示例 46.1。使用 boost::lockfree::spsc_queue
#include <boost/lockfree/spsc_queue.hpp>
#include <thread>
#include <iostream>
boost::lockfree::spsc_queue<int> q{100};
int sum = 0;
void produce()
{
for (int i = 1; i <= 100; ++i)
q.push(i);
}
void consume()
{
int i;
while (q.pop(i))
sum += i;
}
int main()
{
std::thread t1{produce};
std::thread t2{consume};
t1.join();
t2.join();
consume();
std::cout << sum << '\n';
}
Example46.1
示例 46.1 使用容器 boost::lockfree::spsc_queue。第一個執行函數 produce() 的線程將數字 1 到 100 添加到容器中。第二個線程執行 consume(),從容器中讀取數字并將它們相加。因為容器 boost::lockfree::spsc_queue 明確支持來自兩個線程的并發訪問,所以不需要同步線程。
請注意,函數 consume() 會在線程終止后被第二次調用。這需要計算所有 100 個數字的總數,即 5050。因為 consume() 在循環中訪問隊列,它讀取數字的速度可能比 produce() 插入數字的速度快。如果隊列為空,pop() 返回 false。因此,執行 consume() 的線程可能會終止,因為另一個線程中的 produce() 無法足夠快地填充隊列。如果執行 produce() 的線程終止,那么很明顯所有數字都已添加到隊列中。第二次調用 consume() 確保將可能尚未讀取的數字添加到 sum 中。
隊列的大小被傳遞給構造函數。因為 boost::lockfree::spsc_queue 是用循環緩沖區實現的,所以示例 46.1 中的隊列容量為 100 個元素。如果由于隊列已滿而無法添加值,則 push() 返回 false。該示例不檢查 push() 的返回值,因為恰好有 100 個數字被添加到隊列中。因此,100 個元素就足夠了。
示例 46.2。 boost::lockfree::spsc_queue 和 boost::lockfree::capacity
#include <boost/lockfree/spsc_queue.hpp>
#include <boost/lockfree/policies.hpp>
#include <thread>
#include <iostream>
using namespace boost::lockfree;
spsc_queue<int, capacity<100>> q;
int sum = 0;
void produce()
{
for (int i = 1; i <= 100; ++i)
q.push(i);
}
void consume()
{
while (q.consume_one([](int i){ sum += i; }))
;
}
int main()
{
std::thread t1{produce};
std::thread t2{consume};
t1.join();
t2.join();
q.consume_all([](int i){ sum += i; });
std::cout << sum << '\n';
}
Example46.2
示例 46.2 與前面的示例類似,但這次循環緩沖區的大小是在編譯時設置的。這是通過模板 boost::lockfree::capacity 完成的,它需要容量作為模板參數。 q 是用默認構造函數實例化的——容量不能在運行時設置。
函數 consume() 已更改為使用 consume_one() 而不是 pop() 來讀取數字。 lambda 函數作為參數傳遞給 consume_one()。 consume_one() 就像 pop() 一樣讀取一個數字,但該數字不是通過對調用者的引用返回的。它作為唯一參數傳遞給 lambda 函數。
當線程終止時,main() 調用成員函數 consume_all(),而不是 consume()。 consume_all() 的工作方式與 consume_one() 類似,但要確保隊列在調用后為空。只要隊列中有元素,consume_all() 就會調用 lambda 函數。
示例 46.2 再次將 5050 寫入標準輸出。
示例 46.3。具有可變容器大小的 boost::lockfree::queue
#include <boost/lockfree/queue.hpp>
#include <thread>
#include <atomic>
#include <iostream>
boost::lockfree::queue<int> q{100};
std::atomic<int> sum{0};
void produce()
{
for (int i = 1; i <= 10000; ++i)
q.push(i);
}
void consume()
{
int i;
while (q.pop(i))
sum += i;
}
int main()
{
std::thread t1{produce};
std::thread t2{consume};
std::thread t3{consume};
t1.join();
t2.join();
t3.join();
consume();
std::cout << sum << '\n';
}
Example46.3
示例 46.3 在兩個線程中執行 consume()。因為有多個線程從隊列中讀取,所以不得使用類 boost::lockfree::spsc_queue。此示例改為使用 boost::lockfree::queue。
多虧了 std::atomic,對變量 sum 的訪問現在也是線程安全的。
隊列的大小設置為 100——這是傳遞給構造函數的參數。但是,這只是初始大小。默認情況下,boost::lockfree::queue 不使用循環緩沖區實現。如果添加到隊列中的項目多于設置的容量,則會自動增加。如果初始大小不夠,boost::lockfree::queue 會動態分配額外的內存。
這意味著 boost::lockfree::queue 不一定是無鎖的。 boost::lockfree::queue 默認使用的分配器是 boost::lockfree::allocator,它基于 std::allocator。因此,此分配器確定 boost::lockfree::queue 是否是無約束的無鎖。
#include <boost/lockfree/queue.hpp>
#include <thread>
#include <atomic>
#include <iostream>
using namespace boost::lockfree;
queue<int, fixed_sized<true>> q{10000};
std::atomic<int> sum{0};
void produce()
{
for (int i = 1; i <= 10000; ++i)
q.push(i);
}
void consume()
{
int i;
while (q.pop(i))
sum += i;
}
int main()
{
std::thread t1{produce};
std::thread t2{consume};
std::thread t3{consume};
t1.join();
t2.join();
t3.join();
consume();
std::cout << sum << '\n';
}
Example46.4
示例 46.3 在兩個線程中執行 consume()。因為有多個線程從隊列中讀取,所以不得使用類 boost::lockfree::spsc_queue。此示例改為使用 boost::lockfree::queue。
多虧了 std::atomic,對變量 sum 的訪問現在也是線程安全的。
隊列的大小設置為 100——這是傳遞給構造函數的參數。但是,這只是初始大小。默認情況下,boost::lockfree::queue 不使用循環緩沖區實現。如果添加到隊列中的項目多于設置的容量,則會自動增加。如果初始大小不夠,boost::lockfree::queue 會動態分配額外的內存。
這意味著 boost::lockfree::queue 不一定是無鎖的。 boost::lockfree::queue 默認使用的分配器是 boost::lockfree::allocator,它基于 std::allocator。因此,此分配器確定 boost::lockfree::queue 是否是無約束的無鎖。
示例 46.4。具有恒定容器大小的 boost::lockfree::queue
原文鏈接:https://yamagota.blog.csdn.net/article/details/127928147
相關推薦
- 2022-04-25 C#使用Npoi導出Excel并合并行列_C#教程
- 2022-07-22 HttpClient如何自定義重試方法
- 2023-05-09 C語言qsort函數用冒泡排序實現過程詳解_C 語言
- 2022-09-16 python解析照片拍攝時間進行圖片整理_python
- 2022-09-29 Python3中map(),reduce(),filter()的詳細用法_python
- 2022-12-09 pygame畫點線方法詳解_python
- 2021-12-04 C語言實現可排序通訊錄的示例代碼_C 語言
- 2022-09-24 opencv實現圖像校正_python
- 最近更新
-
- 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同步修改后的遠程分支