我在一個專案上使用 C 11,這是一個函式:
void task1(int* res) {
*res = 1;
}
void task2(int* res) {
*res = 2;
}
void func() {
std::vector<int> res(2, 0); // {0, 0}
std::thread t1(task1, &res[0]);
std::thread t2(task2, &res[1]);
t1.join();
t2.join();
return res[0] res[1];
}
功能就是這樣。您會看到有一個std::vector,它存盤了執行緒的所有結果。
我的問題是:會std::vector導致虛假分享嗎?如果可以,有什么方法可以避免在使用std::vector存盤執行緒結果時出現錯誤共享?
uj5u.com熱心網友回復:
std::vector 會導致錯誤共享嗎?
容器不是“導致”錯誤共享的東西。它正在寫入可能導致錯誤共享的物件。具體來說,在一個執行緒中寫入與在另一個執行緒中訪問的另一個物件位于同一“快取行”中的物件會導致錯誤共享。
陣列的元素在記憶體中是相鄰的,因此陣列的相鄰小元素很可能在同一快取行中。Vector 是一種基于陣列的資料結構。在您的示例中訪問向量元素的模式是錯誤共享的一個很好的示例。
在使用 std::vector 存盤執行緒結果時,有什么方法可以避免錯誤共享?
不要從多個執行緒寫入陣列(或向量)的相鄰小元素。避免它的方法是:
- 將陣列劃分為連續的段,并且只能從單獨的執行緒訪問任何單獨的段。磁區的大小必須至少是目標系統上高速快取行的大小。
- 或者,寫入單獨的容器,并在執行緒完成后合并它們。
uj5u.com熱心網友回復:
是的,如果你寫入 a 中的兩個相鄰int元素std::vector,它們很可能都在同一個快取行上,如果這個快取行被兩個不同的執行緒同時訪問,這將導致錯誤共享。
引入了 C 17 std::hardware_destructive_interference_size,這是一種可移植的方式,可以從編譯器獲取有關目標平臺上預期的 L1 快取行大小的提示。
因此,為了防止錯誤共享,您應該確保兩個int變數至少std::hardware_destructive_interference_size相隔位元組:
void func() {
constexpr int min_offset = std::hardware_destructive_interference_size / sizeof(int);
std::vector<int> res( min_offset 1, 0 );
std::thread t1( task1, &res[0] );
std::thread t2( task2, &res[min_offset] );
t1.join();
t2.join();
return res[0] res[min_offset];
}
但是,在撰寫本文時,一些編譯器(尚)不支持std::hardware_destructive_interference_size. 有關詳細資訊,請參閱此問題。
如果您想合理確定您的代碼在不久的將來不會發生錯誤共享,那么您可能需要假設快取大小是std::hardware_destructive_interference_size.
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/408001.html
標籤:
上一篇:ExcelVBA-匯出為CSV
下一篇:C 懸空參考奇怪的行為
