2010-06-30 106 views
0

在Outlook中添加一個,我有一個工作線程做了一些處理,然後更新布爾標誌。主線程檢查這個標誌,如果這是錯誤的,它只是處理一個while循環而什麼也不做。如何訪問2個線程之間的共享資源?

 
//worker thread 
void DoSoneThing() 
{ 
Outlook.Recipients recps = mail.Recipients. 
foreach(Outlook.Recipient recp in recps) 
{ 
//Save each recipients in a colection 
} 
isDone=true; 
} 


//Main thread 
while(!isDone) 
{ 
//read the collection where recipients name have been stored. 
}`` 

如果主線程談到這段代碼的工作線程設置標誌爲true,主線程之前不斷處理迴路和secondry線程是正中下懷暫停。並且由於isDone標誌從不設置爲true,所以主線程不會執行任何操作。

當我在DoSomeThing方法中放入一個鎖並在mian線程中使用相同的鎖時,此問題已得到解決。

 
myClass 
{ 
public static object _syncRoot = new Object(); 
void DoSoneThing() 
{ 
lock(_syncRoot) 
{ 
//process 
isDone=true; 
} 
} 
} 

myOtherClass 
{ 
    lock(myClass._syncRoot) 
{ 
//process 
} 
} 

我的理解是鎖用於限制由一個以上的線程的項,以相同的一段代碼。但不明白爲什麼工作線程在共享資源被主線程訪問時沒有做任何事情。

+0

你跳過所有的(但非常值得做的正確的情況下)。重要的邏輯。請發佈Main和DoSomething的實現。 – 2010-06-30 14:02:05

回答

2

我認爲這裏可能存在輕微的概念問題。

首先,我可以建議的

while(!isDone) 

不是等待一個偉大的方式 - 它被稱爲「旋轉」,並允許線程使用處理器的時候,它沒有做任何事情,這是沒有效率的。 (在某些特定情況下旋轉鎖可能會有問題,但在用戶應用程序中通常不是一個好計劃。)

鎖,使一個線程等待,而其他進程更好。

現在,至於你的具體問題。在while測試已經被優化的情況下讀取isDone標誌是可能的(例如,編譯器'知道'它不會改變,所以它不會放入任何代碼來再次從內存中獲取它 - 它只是測試相同的CPU寄存器)。您可以通過使用'volatile'修飾符來告訴編譯器必須從內存中重新獲取值,從而克服這一點。 也可能是主線程正在旋轉,從而導致另一個線程不能正常工作(儘管人們希望它最終會在一個'公平'系統中運行)。

無論後者,在等待另一個線程完成處理時有一個線程旋轉是應該避免的,除非檢查了該標誌,否則它會轉而執行一些有用的操作(例如更新GUI)。

你必須要非常小心多線程的設計 - 他們是複雜的,可以有晦澀和難以預知的行爲

+0

謝謝拉格斯特。我知道這不是一個好的設計,我會繼續努力。我同意你的第一個理由,我會去檢查易變的。但由於後一個原因,如果郵件線程使另一個線程餓死,那麼當我使用鎖定而不是旋轉循環時,它是如何開始工作的? – Kapil 2010-06-30 15:06:56

+0

嗨Kapilg。當你使用Lock時,你讓操作系統知道沒有訪問權限的線程應該等待訪問 - 這就是線程變得不可調度,並且Windows不會爲它分配任何處理器時間。在那種情況下,它不會因爲暫停而使其他線程陷於飢餓。那有意義嗎? – Ragster 2010-06-30 15:36:24

+0

絕對:) :) – Kapil 2010-06-30 15:43:50