2013-11-22 27 views
0

我在做多線程的時候非常瞭解,儘管頭疼得厲害,但我仍然覺得它非常迷人。我正在使用qt並且一直在檢查教程,發現一個完全適用於我的情況,即將數據流式傳輸到循環緩衝區,一個線程寫入它,一個線程讀取它。這是教程here。首先讓我問你是否在等待條件下選擇了正確的方法。爲什麼我在使用qt等待條件時不必在鎖定/解鎖語句中進行換行?

我選擇不使用信號量,因爲緩衝區的大小可能會隨時從主線程中改變,導致重新分配和重新調整讀/寫索引,並且調整信號量不會顯得那麼容易。我不希望在循環中放置一個if是否要執行循環體,因爲它必須一遍又一遍地執行,直到它可以在緩衝區中放入更多數據爲止,所以等待條件是我的自然解決方案。

其次,我對他們的例子中的等待條件是什麼感到困惑。看起來他們鎖定了互斥鎖,檢查等待條件並阻止,當條件滿足時繼續,然後在那裏解鎖互斥鎖。這並不意味着在這一點上對緩衝區的訪問是完全不受保護的嗎?

第三,當我的主線程想停止時,如何結束這些線程,我有點不知所措。我不能使用等待條件,因爲我希望它們只要主線程希望就運行,並且我不認爲我可以通過線程發出信號告訴它退出。是唯一的方法來通知線程停止執行,如果某個地方經常檢查每個循環中位於主線程中的布爾,然後等待線程在析構函數中退出,那麼唯一方法是通知線程停止執行。問題在於,在等待條件下,我必須首先設置bool退出,然後喚醒這兩個線程。我真的很困惑在這裏做什麼,任何建議表示讚賞。

回答

1

緩衝器的訪問通過憑藉數據的索引如何選擇保護:

  1. 消費者看到在緩衝器所以塊中沒有數據
  2. 生產者看到緩衝器未滿因此寫入在索引0
    在緩衝器中的一些數據,並喚醒該消費者並遞增索引的索引t寫1
  3. 消費者看到數據,並在索引0
  4. 讀取

特別是從消費者的唯一途徑i % buffersize是一樣i % buffersize從關鍵部分之間的生產者,如果numUsedBytes == 0,你是生產商或numUsedBytes == buffersize,你是消費者

看到這個你應該可以推論,無論是生產者還是消費者將能夠同時讀取或寫入相同指數:ERGO訪問被保護

solution is well researched

有幾個問題儘管如此:如果條件因任何原因而被喚醒,if檢查是不夠的。測試`TimeToEnd`時

{ 
    QMutexLocker lock(mutex.lock()); 
    while (numUsedBytes == BufferSize) 
    { 
     bufferNotFull.wait(&mutex); 
     if(shouldStop)return; 
    } 
} 
+0

關於QMutexLocker的問題,文檔告訴我它所做的只是鎖定構造函數中給出的互斥鎖,然後在其銷燬時解鎖。在循環過程中,互斥鎖永遠不會被銷燬,所以何時鎖定和解鎖互斥鎖以訪問shouldStop,numUsedBytes,bufferSize和buffer?基本上他們爲什麼必須將等待語句包裝在鎖定/解鎖塊中呢? – FatalCatharsis

+0

儲物櫃在超出範圍時被破壞,所以在我的代碼退出並離開花括號後,然後儲物櫃被破壞,互斥鎖解鎖 –

+0

好吧,我明白了,我的意思是關於發生在while循環。在他們的例子中,他們將mutex.lock()和mutex.unlock()中的if和wait條件包裝起來,但在你的例子中,你所做的只是等待。他們這樣做的目的是什麼? – FatalCatharsis

1

首先,是的,等待條件是這項工作的正確工具。

他們對等待條件的使用並不是最好的,因爲有時一個線程會提前被喚醒。他們的if語句應該是一個while循環,例如

while (numUsedBytes == 0) 
    bufferNotEmpty.wait(&mutex); 

二,生產者和消費者都濃墨重彩,使生產者擁有一些在緩衝區中的字節,而消費者擁有了別人。也就是說,消費者擁有未經檢驗的數據部分,產品擁有未使用的部分。這就是爲什麼他們可以安全地讀或寫緩衝區中的一個字節,因爲他們保證另一個線程不使用該字節。

第三,像這樣結束的線程很困難,但你的想法大多是正確的。如果主程序知道什麼時候是時候結束,然後更改等待循環,以這樣的:

while (numUsedBytes == 0) 
    bufferNotEmpty.wait(&mutex); 
    if (TimeToEnd) {unlock(); return;} 

,並在主,當它的時間來結束你說

lock(); 
TimeToEnd = true; 
wakeAll(); 
unlock(); 
joinAllThreads(); 

如果生產者知道當到了結束的時候,會發生一些非常相似的事情,主程序在創建所有線程後立即加入所有線程。

+0

各地,同時身體不要有也括號:他們應該使用QMutexLocker所以異常或早收益不會搞砸一切。 –