2012-02-15 153 views
0

如果有2個線程試圖同時寫入同一個對象的代碼,我的理解是它不會產生任何編譯時錯誤,這是調試多線程的部分原因計劃是如此困難。但是這會產生運行時錯誤/異常嗎?調試多線程程序

任何人都可以提出任何好的多線程調試技術?

謝謝。

回答

1

從兩個或多個不同的線程中訪問同一個對象不會在運行時或調試器中產生錯誤,但它很可能會以您不打算的方式繞過對象。

在多線程環境中安全地處理它的方法是使用互斥鎖和信號量。 對於互斥鎖,請檢查wikipedia link

互斥鎖通常用於當您想限制一次只有一個線程訪問對象的情況。

另一方面,信號量是一個更一般的情況(互斥量實際上是一個信號量的特例),它有一個計數器,每個線程將根據信號量的激活/停用而增加/減少。當信號量達到0時,它將鎖定自己和導致它的線程。有關信號量的更多信息,請查看wikipedia page

如果您需要更具體的建議,那麼我建議您向我們提供有關您所使用的操作系統和/或您所使用的API的信息,因爲任何與線程(互斥鎖,信號量等)是操作系統特定的

+0

Lefteris調試多線程代碼,感謝您的回覆。我正在使用Boost庫,並試圖在Windows和Linux上創建一個跨平臺的應用程序。我對多線程編程相當陌生,對於不同的通信技術我很困惑。 互斥和信號燈如你所說,我也聽說過使用同步消息隊列。只是想知道是否有任何「標準」方法。 謝謝。 – 2607 2012-02-15 05:57:49

+0

這就是我想要實現的。我有一個M對象的向量,每個對象都有N個成員變量。有X個線程,每個線程可以訪問矢量內任何對象的任何成員變量。我試圖達到這個目標,並且也有最低限度的關鍵部分,即每次儘可能少的阻止。謝謝。 – 2607 2012-02-15 05:59:15

+0

如果你想訪問是獨立的muttualy,那麼當你必須使用N個互斥鎖時,只有一個線程可以訪問N個成員變量之一。我不熟悉boost庫,但我相信它具有互斥功能,對吧? – Lefteris 2012-02-15 06:25:50

1

兩個不同的線程同時寫入單個對象或資源會破壞它,這個問題是一個競爭條件。在多線程程序中,競態條件既不是編譯時錯誤,也不是運行時錯誤/異常。競爭條件是管理共享資源,即進程間通信的軟件缺陷,並且因爲它們破壞幕後數據而令人討厭。多次運行相同的程序將導致輸出結果是預期結果,而在其他時間不是預期結果。

使用互斥排除線程中的競爭條件。如果只有一個對象或資源可用,則使用互斥鎖,例如LCD顯示器或單個對象,否則如果有多個使用信號量,則有一個示例是四個USB端口。資源是數據和設備。數據是變量,對象,數據結構等。設備是LCD顯示器,打印機,USB端口等。

將程序視爲順序單線程並決定需要完成的分離任務可以節省麻煩更多的時間調試。字處理器是一個多線程程序,由幾個線程組成。線程的想象示例是:讀取文本文件,顯示文本,保存文本文件,並可能每5分鐘運行一次自動保存。線程應該是可以執行的動作,並注意文字處理器中的所有線程都將文本作爲資源。

如果您已經擁有代碼或檢查值,請在每個線程中的對象之前和之後使用printf語句而不是cout。查看printf的原因,而不是cout here

所有操作系統都有進程間通信,但API不同。 Linux使用POSTIX API,Windows使用Win32或Windows API,但使用方法相同。

閱讀材料 http://drdobbs.com/cpp/199200938?pgno=1

^-Summarized一些文章到寫着什麼

0

它可能會或可能不會的。大多數線程標準的併發修改都是基於UB的,所以他們不能保證會發生什麼。通常,對於簡單類型,其中一個或另一個寫入將「贏」。 (有些平臺可以保證對齊,簡單的類型。)對於複雜的類型,您可能會撕裂並以「中間值」結束。

併發寫入通常不是你有,雖然問題的類型。更常見的情況是重疊讀取 - 修改 - 寫入操作。例如,考慮嘗試將一個項目添加到同一個隊列或鏈接列表的兩個線程。當你添加一個項目到一個鏈表時,可能會有一段時間,鏈接列表被「破壞」,並且如果另一個線程在鏈接列表被破壞的時候訪問鏈接列表(在修改過程中,當它部分完成時),事情可以爆炸。

添加項目到鏈表的頭通常涉及這樣的:

object->next = head->next; 
head = object; 

如果另一個線程試圖對象的第一行完成後,但在第二行開始之前添加到鏈接列表,結果不會很漂亮。

1

如果你在Linux或OS X,那麼你可以使用的工具Valgrind的(hellgrind或DRD)一個檢測某些內存訪問的線程,而相應的互斥。

但是這不是萬無一失的,我不會依靠它來捕捉你所有的問題..很有可能任何共享資源。

0

似乎沒有人回答瞭如何實時調試多線程代碼,這真的很難。只有非常短的延遲纔會使程序的行爲有所不同,並且只有在某些競爭狀況發生時纔會發生錯誤。這隻能通過非常快速的跟蹤來調查,因爲Visual Studio的速度太慢了。更糟的是,當兩個線程同時調用跟蹤方法時,trace方法變得非常慢。

這是很容易給自己的,非阻塞(!)跟蹤寫入到內存中。只需將信息寫入環形緩衝區即可。我的C++不夠好,但在C#代碼將是這個樣子:

const int maxMessages = 0x100; 
const int indexMask = maxMessages-1; 
string[] messages = new string[maxMessages]; 
int messagesIndex = -1; 

public void Trace(string message) { 
    int thisIndex = Interlocked.Increment(ref messagesIndex) & indexMask; 
    messages[thisIndex] = message; 
} 

這種方法也收集線程和定時信息,並輸出跟蹤好聽點是在一個更詳細的描述: CodeProject上:實時1