[英]c++ multithreading shared resources
我正在嘗試使用Boost庫對一段代碼進行多線程處理。 問題是每個線程必須訪問和修改幾個全局變量。 我正在使用互斥鎖來鎖定共享資源,但是與沒有多線程的程序相比,該程序最終要花費更多的時間。 關於如何優化共享訪問的任何建議?
非常感謝!
在下面的示例中,* choose_ecount *變量必須被鎖定,並且我無法將其移出循環,並且只能在循環結束時鎖定它以進行更新,因為內部函數需要使用最新值。
for(int sidx = startStep; sidx <= endStep && sidx < d.sents[lang].size(); sidx ++){
sentence s = d.sents[lang][sidx];
int senlen = s.words.size();
int end_symb = s.words[senlen-1].pos;
inside(s, lbeta);
outside(s,lbeta, lalpha);
long double sen_prob = lbeta[senlen-1][F][NO][0][senlen-1];
if (lambda[0] == 0){
mtx_.lock();
d.sents[lang][sidx].prob = sen_prob;
mtx_.unlock();
}
for(int size = 1; size <= senlen; size++)
for(int i = 0; i <= senlen - size ; i++)
{
int j = i + size - 1;
for(int k = i; k < j; k++)
{
int hidx = i; int head = s.words[hidx].pos;
for(int r = k+1; r <=j; r++)
{
int aidx = r; int arg = s.words[aidx].pos;
mtx_.lock();
for(int kids = ONE; kids <= MAX; kids++)
{
long double num = lalpha[hidx][R][kids][i][j] * get_choose_prob(s, hidx, aidx) *
lbeta[hidx][R][kids - 1][i][k] * lbeta[aidx][F][NO][k+1][j];
long double gen_right_prob = (num / sen_prob);
choose_ecount[lang][head][arg] += gen_right_prob; //LOCK
order_ecount[lang][head][arg][RIGHT] += gen_right_prob; //LOCK
}
mtx_.unlock();
}
}
從您發布的代碼中,我只能看到對choose_ecount和order_ecount的寫入。 那么,為什么不使用局部每線程緩沖區來計算總和,然后在最外層循環之后將它們加起來,僅同步此操作呢?
編輯:如果您需要訪問choose_ecount的中間值,您如何確保存在正確的中間值? 一個線程可能同時完成了其循環的2次迭代,同時在另一個線程中產生了不同的結果。
聽起來好像您需要在計算中使用障礙。
在內部循環中使用互斥鎖不太可能獲得可接受的性能。 並發編程非常困難,不僅對於程序員而言,對於計算機而言也是如此。 現代CPU的大部分性能來自能夠將代碼塊視為獨立於外部數據的序列。 對於單線程執行有效的算法通常不適合於多線程執行。
您可能想看一看boost::atomic
,它可以提供無鎖同步,但是原子操作所需的內存屏障仍然不是免費的,因此您仍然可能會遇到問題,您可能必須重新執行想想你的算法。
我猜想您將完整的問題分為從startStep
到endStep
的各個endStep
以由每個線程進行處理。
由於那里有鎖定的mutex
,因此可以有效地序列化所有線程:將問題分成一些塊,這些塊按串行但未指定的順序處理。 那唯一得到的就是執行多線程的開銷。
由於您在double
進行操作,因此不建議您使用原子操作:它們通常僅針對整數類型實現。
唯一可能的解決方案是遵循Kratz的建議,為每個線程復制一個choose_ecount
和order_ecount
,並在線程完成后將它們縮減為一個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.