我正在使用一個開源模擬軟體,可以使用支持 OpenMP 的 cmake 選項進行編譯。( https://github.com/oofem/oofem/ )
在我的課堂上,我在 for 回圈中呼叫以下方法:
MaterialStatus *
Material :: giveStatus(GaussPoint *gp) const
/*
* returns material status in gp corresponding to specific material class
*/
{
MaterialStatus *status = static_cast< MaterialStatus * >( gp->giveMaterialStatus() );
if ( status == nullptr ) {
// create a new one
status = this->CreateStatus(gp);
// if newly created status is null
// dont include it. specific instance
// does not have status.
if ( status ) {
gp->setMaterialStatus( status );
}
}
return status;
}
(這里是Github 存盤庫中上述代碼的鏈接。)
正如您在 giveStatus 方法中看到的,如果尚未分配狀態,它將創建并分配一個,但如果您呼叫gp->setMaterialStatus(gp)并且已經有一個狀態實體分配給gp,則代碼將停止并出現錯誤。
現在我的問題是,如果我不使用 OpenMP 編譯代碼,代碼將可以正常作業,但如果我使用支持 OpenMP 的編譯,代碼將停止并顯示狀態已分配的錯誤。
我不確定發生了什么,我認為兩個物件試圖從同一個gp獲取狀態,并且由于沒有分配狀態,執行緒無法獲得 *狀態指標,并且它們都嘗試多次設定狀態。
在除錯時如何獲取有關此問題的更多資訊以及如何解決此問題?
uj5u.com熱心網友回復:
giveStatus顯然不是執行緒安全的。因此,從多個執行緒并行呼叫它會導致競爭條件。事實上,一些執行緒可以同時檢查是否status是null并且可以并行進入條件。然后status由多個執行緒設定,導致未定義的行為(通常是取決于執行緒執行順序的結果)。因為此代碼并非設計為執行緒安全的,所以最簡單的選擇是放置臨界區以保護代碼(即,一個執行緒一次將執行該部分,因此函式)。這可以使用指令來完成#pragma omp critical。如果您希望執行是確定性的,最好使用#pragma omp master因此強制相同的唯一執行緒執行代碼,然后使用同步(例如屏障、原子、臨界區等)將其結果共享給其他人。
或者,您可以重寫代碼以實作執行緒安全。為此,您通常不需要使用(隱藏的)狀態機并支持執行緒本地存盤。OOP 代碼往往不是很好,因為 OOP 代碼的主要目標是抽象狀態機(通過封裝)。
uj5u.com熱心網友回復:
您的代碼中的問題是Material物件作用于 aGaussPoint并且沒有進一步的背景關系,就無法查看兩種材料是否不作用于同一個高斯點。因此,您有一個競爭條件。對于可并行化的代碼,您需要將此代碼橫向翻轉并考慮所有高斯點并詢問它們與材料的互動。
以我自己的表述方式,您使用的是“推送”模型,其中一個物件將狀態推送到其他類的多個物件上。對于執行緒安全的公式,您需要轉置它并使用“拉”模型,其中其他類物件收集所有動作。為什么我說“轉置”?好吧,可以將其視為對矩陣向量乘法的非常抽象的描述。在“拉”模型中,每個輸出點都是(矩陣行的)與整個源向量的內積。在“推”模型中,每個輸入點都將(矩陣列的縮放)添加到整個輸出中。所以一個是另一個的轉置積公式。
還有一些適合你的并行哲學。
哦,至于你的直接問題:OpenMP 讓你在腳下開槍。它不會檢測到沖突。你必須自己避開它們。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/457403.html
上一篇:真正的無鎖MPMC環形緩沖區?執行緒能夠互相幫助避免阻塞嗎?
下一篇:如何使用QtConcurrrentQt6運行成員函式?型別'decay_t不能在'::'之前使用,因為它沒有成員)
