2013-01-08 85 views
1
public void Remove(T item) 
{ 
    locker.EnterWriteLock();   
    try 
    { 
     list.Remove(item); 
    } 
} 

以上是實例類的方法。說實例是myObject。 關於上述片段,我的問題是這樣的:方法參數線程安全嗎?

線程調用myObject.Remove(A)
線程執行locker.EnterWriteLock()

線程兩個調用myObject.Remove(B)

線程1進入try塊並執行list.Remove()

此時item的值是多少?即list.Remove()將以A或B作爲參數被調用?

+2

它們是什麼類型的'locker'變量? –

+0

ReaderWriterLockSlim – Sam

+0

這個問題本來很容易通過調試和檢查來解決。如果你發現答案的問題會更好。 –

回答

3

每個線程都有自己的調用堆棧,方法參數存儲在該堆棧上。線程之間不共享堆棧。

在線程堆棧中,有一行表示調用了Remove,並且包含「A」或對「A」的引用(取決於它是值還是引用類型)。

當線程2進入方法時,它有自己的調用堆棧(線程1的堆棧在線程2運行時未使用),其中有一行指示Remove項目「B」的開始。然後該線程被暫停,它的調用堆棧未被使用,我們回到線程1,其中項目「A」是調用堆棧上的內容。

在未來線程中的某一時刻,兩個將被重新激活,並且在它的調用堆棧上將具有項「B」。

+0

小糾正,'...參數存儲在該堆棧上。' –

+0

是的,每次調用Remove類型都會創建一個新的Remove的「實例」。 –

0

我懷疑你應該在這裏鎖定的是list變量。您正在調用其上的Remove方法,如果list變量是某種非線程安全的類型,例如List<T>,例如,如果在同一個實例myObject上的多個線程同時調用此方法(這是你的list現場生活)。就方法的論點而言,在方法的範圍內很難談論它們的線程安全性。

+0

瞭解。我的問題是 - 當我實際上在列表中調用Remove時,我會用A還是B來調用它? – Sam

+0

鑑於我們沒有跡象表明'locker'的範圍是我們無法真正對此發表評論的。他可能會也可能不會鎖定在合適的範圍內,但這與他的問題無關。它比這更基礎。 – Servy

+0

你會用參數的任何值調用它。因此,例如,如果您使用A調用方法,則A將傳遞給remove方法。方法參數存在於堆棧中。 –

0

.Net不提供任何繼承鎖定參數。然而,list.Remove(item)不會修改item(假設它是標準的System.CollectionsSystem.Collections.Generic實現)並且使用不同參數調用相同的方法兩次會創建item(每個方法調用一個)的兩個副本,而不是一個。

相反,我會鎖定列表,因爲大多數類的實例方法不保證是線程安全的。

0

線程2將在locker.EnterWriteLock();等待線程1執行locker.ExitWriteLock();

所以線程2之前線程1調用locker.ExitWriteLock();

只是不能訪問list如果擔心參數item,確保它穿過堆棧和每個線程都有自己的一個,所以item真的不能被另一個線程「替換」...

所以答案是:如果線程1調用locker.EnterWriteLock(); befo重新線程2,A將在B之前被刪除。

1

方法參數分配在調用該方法的線程的堆棧上。因此,每一個線程都有自己的論點,而且不會互相影響。

0

item的值將是A參數的值。

只有行locker.ExitWriteLock已執行行將該塊將可用線程之一。