2011-10-05 152 views
1

簡單版:在一個C++程序中,我使用兩個不同的線程來處理一些整數變量。但我相信一個人總是在寫一些價值,另一個人只是在閱讀那篇文章。在讀取/寫入數據時是否還需要使用互斥鎖?確實需要使用互斥鎖嗎?

現在的細節:主要思想是第一個線程生成一些信息並將它們保存到一個數組中,第二個線程從該數組中讀取數據並處理它們。這個數組表示一個隊列。這意味着我有兩個索引值指向隊列中的第一個和最後一個項目。現在我想知道,如果我在讀取或寫入數值時必須鎖定這兩個索引值,還是可以不鎖定地檢查它們?請注意,生成器線程是queue_back的唯一線程更改索引,並且處理器線程具有更改queue_front的獨佔權限。

如果我正在爲基於Linux的系統開發任何更改,並使用gcc編譯代碼。 PS:在一些使用線程的代碼中,我看到關鍵字volatile圍繞着不同線程之間共享的變量,我是否也需要使用它呢?

+0

如果未使用volatile,其他線程可能會或可能不會看到對該變量所做的更改。 –

回答

3

否讀取和寫入不是原子的,您需要使用某種同步機制對其進行同步。另外,您必須將共享整數標記爲volatile,否則優化器可能會認爲該變量永遠不會在您的一個線程中更新。

gcc允許您對int,long和long long(以及它們的未簽名對象)執行原子操作。

查找的功能:

type __sync_fetch_and_add (type *ptr, type value); 
type __sync_fetch_and_sub (type *ptr, type value); 
type __sync_fetch_and_or (type *ptr, type value); 
type __sync_fetch_and_and (type *ptr, type value); 
type __sync_fetch_and_xor (type *ptr, type value); 
type __sync_fetch_and_nand (type *ptr, type value); 
+0

正要輸入類似的東西。 –

+1

建議編輯「會認爲」「可能會想」。 –

+0

@JohnDibling:同意和修改。 –

1

是的,你需要一個互斥體,關鍵段,聯鎖接入等同步訪問變量,既可以確保讀取線程不寫入線程仍然保存它們時讀取不完整的字節。這對於多核/ CPU系統來說尤爲重要,在這些系統中,兩個線程可以真正並行訪問變量。

+0

如果將數組的大小限制爲256,並將索引值限制爲單個字節的數據,該怎麼辦? – Ali1S232

0

是的,您需要通過使用某種同步機制(如互斥鎖)來保護生成器和讀取器線程中的隊列索引。

HTH

+1

等一下,真的嗎?編譯器不允許優化它呢?我不認爲這是正確的。這是'volatile'關鍵字的唯一用法。 –

+0

@Minging Duck - 是的,你是對的,我錯了。我改變了答案。感謝您接受它。 –

0

如果你真的只是共享一個單一的整數,然後std::atomic<int>聽起來像是正確的類型使用,從<atomic>頭。 (如果你有一箇舊的編譯器,還應該有Boost或TR1版本。)這確保了原子讀取和寫入。據我所知,不需要volatile限定詞。

+0

好吧,它不僅僅是一個整數,我分享,但只有一個整數可以在同一時間訪問。我的意思是整個隊列變量是共享的,但是兩個線程在嘗試訪問隊列節點之前首先檢查頭部和尾部變量。 – Ali1S232

1

讀取和寫入正確對齊的數據不超過機器字(通常任何int可以解決的問題)在大多數主要體系結構上都是原子的。那不是是指架構。

這意味着不,您不能只讀headtail並期望數據是一致的。但是,例如,如果sizeof(int)碰巧是4,而sizeof(short)碰巧是2,並且如果您不關心「非主流」平臺,則可以進行一些聯合欺騙並在沒有原子操作或互斥體的情況下離開。

如果您希望自己的代碼具有可移植性,則無法實現正確的鎖定或原子比較/交換。

關於volatile,這插入用於Microsoft Visual C++(作爲一個特定的編譯器狡辯)記憶障礙,但標準不保證什麼特別的東西以外,編譯器不會優化變量。就目前而言,製作volatile並沒有什麼幫助,它確保了線程的安全性。

1

在讀取/寫入數據時,我仍然需要使用互斥鎖嗎?

是的,你需要一個鎖。您可能對稱爲讀/寫鎖的更具體實現感興趣。

您還可以使用原子和/或內存屏障。使用這些將需要更好地理解您的目標體系結構。重現多線程錯誤可能非常困難,而這些替代方案應該被認爲是可能不便攜的優化。

我看過關鍵字在不同線程之間共享變量,我是否也需要使用它呢?

哎呀。沒有!這不是C++中多線程讀取和寫入的安全或可移植解決方案。代之以使用原子,鎖定,複製,不可變和純粹的實現(等等)。

volatile解讀可以通過平臺和/或編譯器而變化,並且它沒有指定的操作用C任何特定方式或C++多線程的目的讀取和寫入(有,它可以被可靠地用作舊假圖例原子讀/寫)。我曾經在一個多線程的C++程序中測試了volatile的有效性(在蘋果的gcc的intel-mac上)。我不會提供結果,因爲它的工作原理是有些人可能會考慮使用它,儘管他們應該不是因爲'幾乎'不夠好。

並限定使用volatile:它存在於我的(大型,嚴格編寫,多線程感知)代碼庫中,僅用於與平臺相關的原子API進行接口。而且完全誠實:早些時候還有其他一些用途,但它們可以並且應該被刪除。