2013-06-28 51 views
2

我想使用boost庫多線程一段代碼。問題是每個線程都必須訪問和修改幾個全局變量。我正在使用互斥鎖來鎖定共享資源,但當程序不是多線程時,程序最終需要更多的時間。有關如何優化共享訪問的任何建議?C++多線程共享資源

非常感謝!

在下面的例子中,* 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(); 
       } 

}

+2

不是沒有看到一些代碼... –

+0

在一些代碼中添加 – langLord

+1

你可以將mutext從最內部的循環中提出並將其向上移動一個級別? –

回答

0

這是不太可能你會在一個內部循環使用互斥體來獲得可接受的性能。併發編程是困難的,不僅僅是程序員,而且也是計算機。現代CPU的大部分性能來自於能夠將代碼塊視爲獨立於外部數據的序列。對於單線程執行有效的算法通常不適合多線程執行。

您可能想看看boost::atomic,它可以提供無鎖同步,但原子操作所需的內存屏障仍然不是免費的,所以您可能仍然遇到問題,您可能必須重新 - 思考你的算法。

1

從您發佈的代碼中,我只能看到寫入choose_ecount和order_ecount。那麼爲什麼不使用本地每個線程緩衝區來計算總和,然後將它們添加到最外層循環之後並僅同步該操作?

編輯: 如果您需要訪問choose_ecount的中間值,您如何確保存在正確的中間值?一個線程可能已完成其循環的2次迭代,同時在另一個線程中產生不同的結果。

這種聲音就像你需要用屏障來代替計算。

0

我想你會將你的完整問題分成從startStependStep的塊,以便由每個線程處理。

由於你有鎖定mutex那裏,你有效地序列化所有線程: 你的問題分成一些塊,它是以串行,但未指定的順序處理。 這是你得到的唯一的東西是多線程的開銷。

由於您使用的是double,所以使用原子操作不是您的選擇:它們通常僅針對整型。

唯一可能的解決方案是按照Kratz的建議,爲每個線程提供choose_ecountorder_ecount的副本,並在線程完成後將其減少爲單個線程。