雖然我知道 QT 宣告只有明確宣告的類是執行緒安全的,但我想了解為什么“const”標記方法 - QPainterPath::contains() - 在沒有任何并發??的情況下在并行回圈中呼叫時會中斷寫操作:
#include <QPainterPath>
#include <omp.h>
#include <iostream>
int main(int argc, char *argv[])
{
QPainterPath path;
path.addRect(-50,-50,100,100);
#pragma omp parallel for
for(int x=0; x<100000; x)
if(!path.contains(QPoint(0,0)))
std::cout << "failed\n";
return 0;
}
上面的代碼在不應該時隨機輸出“失敗”。
我的理解是它正在以某種方式改變其內部狀態,盡管方法是“const”:https : //code.woboq.org/qt5/qtbase/src/gui/painting/qpainterpath.cpp.html#_ZNK12QPainterPath8containsERK7QPointF
我需要比較點是否在多個執行緒的路徑內(以加快處理速度),但它不適用于 QPainterPath。即使我為每個執行緒創建了物件的副本,QT 也會在寫入時復制,除非我更改派生物件(以強制其分離),否則結果仍然是相同的錯誤行為,因為它仍在使用相同的共享資料。如果沒有這個丑陋的黑客,我怎么能以安全的方式做到這一點?
uj5u.com熱心網友回復:
答案在您鏈接到的第一行代碼中:
if (isEmpty() || !controlPointRect().contains(pt))
controlPointRect() 有以下內容:
if (d->dirtyControlBounds)
computeControlPointRect();
并computeControlPointRect()執行以下操作:
d->dirtyControlBounds = false;
...
d->controlBounds = QRectF(minx, miny, maxx - minx, maxy - miny);
換句話說,如果controlPointRect() 并行呼叫,可能會發生以下情況:
- 執行緒 T1 看到
d->dirtyControlBounds并進入computeControlPointRect()清除它。它開始計算邊界。 - 執行緒 T2 進入
controlPointRect()并看到這d->dirtyControlBounds是錯誤的。它檢查d->controlBounds(此時是一組空點)是否包含該特定點。它沒有,所以它回傳 false。 - 執行緒 T1 完成并更新
d->controlBounds。從現在開始所有執行緒都是同步的。
這個特定實體的明顯修復是確保在進入大規模并行計算之前清除所有臟位,但這可能不適用于所有物件。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/378500.html
標籤:C qt openmp qpainterpath
