2012-03-24 61 views
1

我一直在困惑於我寫的多線程應用程序的問題。簡而言之,主線程啓動一個熱負載線程,該線程接受文件對象的列表(向量),檢查其時間戳,並將更改的文件傳遞給另一個向量。在多線程應用程序中使用向量

當我嘗試將新文件添加到需要檢查的文件列表時,會發生此問題。熱加載線程不斷檢查其列表中的文件以進行更改,並在迭代時使用範圍鎖定來鎖定/解鎖互斥鎖。同樣,當主線程調用addItems()函數時,同樣的互斥鎖也同樣被鎖定,並添加新文件。

我讀過的信息說這應該罰款給予適當的鎖定,它確實有效,但我經歷了一個非常大的減速作爲結果。也就是說,如果我連一個文件添加到列表中,該計劃不斷減慢,彷彿線程越來越鎖定...

代碼:

void MyThread::addItems(ItemList newItems) 
{ 

    ScopedLock<Mutex> lock(itemMutex_); 


    for (ItemList::iterator it = newItems.begin(); it != newItems.end(); ++it) 
    { 
     if (... test condition on (*it) ...) 
      items_.push_back((*it)); 
    } 
}; 

void MyThread::run() 
{ 
    _done = false; 
    do 
    { 
     YieldCurrentThread(); 

     if (!isEmpty_) 
     { 
      ScopedLock<Mutex> lock(itemMutex_); 
      for (ItemList::iterator it = items_.begin(); it != items_.end(); ++it) 
      { 
       if (... test condition on (*it) ...) 
        updatedItems_.push_back((*it)); 
      } 
     } 
    } 
} 

的run()函數中,當然,不斷運行,迭代我的items_vector,並使用從另一個線程調用的addItems()函數將項插入到vector中。只有一個線程調用addItems()。

它不可能是困難的,但我沒有看到任何東西在那裏,暗示我還沒有嘗試過的解決方案......

編輯:

  1. 註釋如下提醒我指出,如果我不調用addItems(),run()函數似乎對應用程序性能沒有任何顯着影響,儘管它可能是浪費的。
+0

它被寫入的方式,它看起來像updatedItems_將不斷地從items_添加相同的項目。 – 2012-03-24 02:35:34

+0

addItems方法未使用items參數。你打算迭代而不是items_? – 2012-03-24 02:42:07

+0

對不起,我修改了代碼以方便閱讀。在addItems()函數中,我犯了拼寫錯誤。他們已被糾正。關於更新的項目,有一個條件測試,它指示自上次檢查文件的時間戳是否發生了變化。如果是這樣,它被推送到更新列表,然後傳回主線程並清除。 – 2012-03-24 02:53:50

回答

2

你在哪個平臺上?如果您正在嘗試監視已更改的文件,則有操作系統工具可爲您高效地執行此操作。在Linux上,這將是inotify。如果您在Windows上,這看起來像是一篇好文章:http://qualapps.blogspot.co.uk/2010/05/understanding-readdirectorychangesw.html

+0

使用Windows。儘量避免使用特定於操作系統的解決方案,但在這種情況下,我可能會被迫使用它。感謝指針。 – 2012-03-24 02:52:17

+0

當然。對於在Windows上試圖解決的問題,有幾個調試良好的解決方案 - 您應該接受它們。你的問題從根本上說不是互斥體和向量,而是你正在做的實際處理(可能不需要做)。 – 2012-03-24 02:57:24

+0

好點。我編輯了我原來的帖子來解決這個問題(如果我理解你的意思),但我肯定會開始尋找其他一些解決方案。 – 2012-03-24 03:08:06

1

您的鎖定將花費很少的時間解鎖。根據YieldCurrentThread的實施方式,如果確實有任何延遲,我認爲延遲會非常短暫。而且,列表中的東西越多,平均越長,addItems在將數據添加到矢量之前需要等待的時間越長。如果你的主線花費很多時間撥打addItems,我肯定會有一些放緩。

有一兩件事你可以嘗試是一個線環,看起來像這樣:

for (;;) 
{ 
    ItemList snapshot; 
    if (!isEmpty_) 
    { 
     ScopedLock<Mutex> lock(itemMutex_); 
     snapshot = items_; 
    } 
    ItemList updated; 
    for (ItemList::iterator it = snapshot.begin(); it != snapshot.end(); ++it) 
    { 
     if (... test condition on (*it) ...) 
      updated.push_back((*it)); 
    } 
    if (!updated.empty()) 
    { 
     ScopedLock<Mutex> lock(itemMutex_); 
     updatedList_ = updated; 
    } 
} 

這裏的想法是採取重處理,並從互斥下將其移出。當然,如果你的實際瓶頸是鎖定爭用,這實際上只會加快速度。如果問題只是更多的文件需要更多時間來檢查,那麼它與多個線程無關。

+0

我很少添加文件。如果我添加一個文件,它會導致應用程序級聯放慢 - 控制返回到應用程序所花費的時間顯着增加,並且會一直持續下去。迭代過程就是這樣做沒有意義。否則,+1會有很好的優化! – 2012-03-24 02:51:43

+0

而沒有別的東西觸及互斥體?讀取'updatedList_'的代碼怎麼樣?如果你經常投票,你會反覆鎖定互斥鎖,現在你的主線程和後臺線程正在互相攻擊。 – 2012-03-24 02:54:36

+0

其實,我有一個單獨的互斥體,因爲我認爲updateList_是一個單獨的資源。我從這裏排除它,因爲我的測試只用addItems()。因此,在這種情況下,在這個線程之外訪問資源的唯一地方是在addItems()中。 – 2012-03-24 03:00:09

相關問題