2012-01-03 76 views
5

我想確認自己對線程的理解,並通過C++中的引用進行傳遞。以下函數線程安全嗎?使用C++進行線程安全並通過參考傳遞

QString sA = "hello"; 
QString sB = "world"; 
bool someFlag = AreStringsEqual(sA,sB); 

... 

bool AreStringsEqual(QString const &stringA, QString const &stringB) 
{ 
    if(stringA == stringB) 
    { return true; } 

    return false; 
} 

我認爲這是線程安全的。我想,如果有人可以證實我的思維過程,或者告訴我,我不知道我在說什麼:)

  • 有在進程的內存SA和SB的兩個副本。一個是在Thread1的堆棧上創建的,另一個是在Thread2的堆棧上創建的。因爲我們通過引用傳遞,每個線程只需要一組內存中的sA和sB來執行函數調用。

  • 如果我們已經通過值傳遞,在進程內存中每個線程都有兩個線程交換處理器控制的進程內存(每個線程有兩個集合)可能有多達四個sA和sB副本。

  • 這裏沒有共享內存,因此該函數是線程安全的。

很抱歉,如果這個問題是超級簡單,線程都炒了我的大腦:)

的PRI

+0

什麼是QString?它是否實現了「==」運算符?如果是這樣,那麼另一個線程可能會在==運算符的執行過程中更改stringA或stringB,從而可能導致它不是線程安全的。 – user1118321 2012-01-03 06:38:36

+1

我在代碼中看不到線索。是's','sB'和'someFlag'全局變量嗎? – ybungalobill 2012-01-03 06:39:47

回答

2

你的問題有點模糊,在哪裏sAsB宣佈。這聽起來像是在一個函數中聲明的,在這種情況下,你是正確的,每個線程都有自己的版本sAsB。但是,他們在全球範圍內宣佈的機會很奇怪,但事實並非如此。如果我正確理解你的問題,你的意思是說這兩個都是在本地範圍內聲明的,所以你的第一點是正確的。同樣,你的第二點也是正確的。

雖然你的第三點很棘手。在你的特定情況下,沒有內存被共享,所以你的程序是一個「線程安全」的程序(不知道這是否是一個很好的方式)。但是,功能AreStringsEqual而不是線程安全。在將來的某個時候,您(或其他人)可能會使用該功能與共享的數據,並且該功能本身無法防範這種用法。

+0

即使它們是在本地作用域中聲明的,它們也是通過引用傳遞的,這意味着其他函數(和線程)也可以訪問這些存儲器位置。 – 2012-01-03 06:44:49

+0

@IlyaKogan:我不確定我是否理解你的觀點。如果你談論我的第一段話,那簡直就是在他的程序中如何計算sA'和sB'的副本,這是他正確的。線程安全問題在我的第二段中提到,我認爲這也是正確的。無論如何,「AreStringsEqual」使用傳遞引用的事實本質上不會讓其他線程或函數訪問「sA」和「sB」(至少在他的實現中)。你能澄清你的觀點嗎? – 2012-01-03 06:57:05

+0

如果我調用'AreStringsEqual(a,b)',然後啓動另一個線程來更改a和b的內容,那麼這個方法將會很脆弱。因此它不是線程安全的。 – 2012-01-03 07:58:10

3

沒有理由爲什麼兩個線程不會持有相同的字符串引用。

此功能是不是線程安全,因爲語句if(stringA == stringB)不是原子的。 首先你從內存中獲取stringA,然後只有string B

讓我們留stringA == stringB == 2

您提取stringA,然後有一個上下文切換,並且stringA和stringB都變爲3.然後您獲取stringB。你的函數會返回false(因爲2 != 3),儘管stringA一直等於stringB

0

首先,不清楚爲什麼你需要兩個相同字符串的副本,如果它們總是具有相同的值。

也許它是基於所描述的上下文的線程安全的,但僅僅是看看它自己的函數,它不是線程安全的,因爲在if條件執行時,字符串的值可能已經改變。

+0

我很確定問題中的代碼僅用於示例目的。無論如何,比較兩個字符串是相當普遍的,這並不是該函數不是線程安全的原因。 – 2012-01-03 06:45:53

1

如果SA和SB在線程之間共享的功能不是線程安全的。

在一個線程中執行AreStringsEqual函數的過程中,另一個線程試圖修改sA或sB或兩者的值是很有可能的,那麼就會出現一個Race條件。

當你的功能沒有改變的價值,你的功能之外的代碼。

因此,最好是按值使用通視則該函數將被保證是線程安全的

2

除非QString已指定operator==線程安全的,堆棧 上的本地副本功能是不是線程安全。 AreStringsEqual的執行本身並不能保護數據。

你把線程安全的客戶端上使用此執行的責任。在AreStringsEqual中,客戶端必須確保參數和參數的內部數據不會變異(例如,通過另一個線程)。因此,他們可能會發現自己有不必要的副本。究竟該如何發生是由QString的執行決定的。甚至std::string實現顯着變化=)

對於併發上下文字符串,一個通常將字符串移動到併發上下文之前採取的副本。如果真的需要共享,你需要一些東西來保護它(比如鎖)。對於原始集合(例如std::stringstd::vector),您將希望避免在每次訪問時鎖定,因爲這會導致性能下降,並可能會相當容易地失敗。所以,如果您必須共享不是明確線程安全的對象,通常會複製或鎖定。

因此,執行AreStringsEqual不是線程安全的(再次,除非bool QString::operator==(const QString&) const保證是線程安全的)。

但是,你使用的AreStringsEqual

QString sA = "hello"; 
QString sB = "world"; 
bool someFlag = AreStringsEqual(sA,sB); 

將罰款爲廣大string實現的,因爲這些參數和他們的數據將是本地的線程。