2009-11-02 115 views
5

假設我有一個模塊,它有一個隊列。.NET - Queue.Enqueue方法線程安全嗎?

其他實體來排隊,他們必須經過一個功能:

public sub InsertIntoQueue(Obj) 
    MyQueue.Enqueue(Obj) 
end sub 

如果我有多個線程運行,他們想打電話InsertIntoQueue(),這被認爲是線程安全的?

我的印象是,只有一條執行InsertIntoQueue()函數所需的內存指令副本......這會導致我認爲這是線程安全的。

但是,我想知道當兩個線程同時嘗試運行該函數時會發生什麼?

此線程是否安全,如果不是,我該如何使線程安全? (以及關於速度和內存使用情況的性能影響是什麼)

回答

4

不,這不是線程安全的。

此類型的公共靜態(Visual Basic中的Shared)成員對於多線程操作是安全的。實例成員不保證是線程安全的。

MSDN Site

我建議增加一個對象來表示同步處理到對象

Dim SyncHandle as Object = new Object() 

和修改方法,例如

Public Sub InsertIntoQueue(Object item) 
    SyncLock SyncHandle 
     MyQueue.Enqueue(item) 
    End SyncLock 
End Sub 
1

一組指令並不意味着它是線程安全的。至於說明,你總是隻有一套。

現在,看看你提供的代碼示例是不可能說它是否是線程安全的。包括Queue在內的所有標準.NET集合本身都不是線程安全的,但可讓您訪問自己的同步版本。

現在在性能上有很大的表現,當然有一個性能影響,有多大 - 取決於鎖的範圍和其他一些事情。特別是在Web應用程序中使用全局鎖可以成爲重負載下的一個嚴重的瓶頸

2

SyncLock MyQueue 
    MyQueue.Enqueue(Obj) 
End SyncLock 

末次

0

截至關OP的話題稍微去的風險,應考慮到隊列的其他方法。我假設至少有一個線程出隊對象,並且可能還要檢查隊列是否爲空?

從出列的角度來看,如果您有多個線程出隊,並且在調用出列隊列之前檢查隊列是否爲空(以防止無效操作異常),那麼完全有可能是一個線程(線程a)可以在隊列中的最後一項出隊,在另一個線程(線程b)讀取隊列不爲空並且它調用出列隊列之間,因此線程a將導致無效操作異常。

你可以把鎖放在空的檢查和出隊檢查周圍來解決這個問題。

Thisthis是關於線程安全有趣的文章,還我可以推薦閱讀this和/或this,而他們是不是所有在vb.net他們詳細解釋線程。

+0

我的計劃是有多個線程入隊,並且一個線程鎖定並以特定間隔刷新整個隊列。 – 2009-11-03 08:16:33

+0

如果在處理隊列中的所有對象時鎖定,則所有排隊的線程都將阻塞(如果它們嘗試入隊),直到您的出隊線程完成爲止,最好鎖定每個線程的空檢查和出隊而不是整個隊列處理。 – Matt 2009-11-03 20:14:01

0

我不是線程安全方面的專家,但我正在努力學習儘可能多的關於這個問題。

我曾經認爲(像你一樣)這個操作可以是線程安全的,就像寫入不同線程上的隊列數據一樣,並且不會執行出列操作。但正如有人在這裏解釋(和無處不在MSDN文檔):

公共靜態(在Visual Basic中的Shared)這種類型的 成員對於 多線程操作安全。實例 成員不保證是線程安全的 。

這意味着,也許在內部的MyQueue.Enqueue(Obj)是這樣完成的:

  1. 穿戴數據上隊列();
  2. 增強隊列指針;

如果在這樣做的話,你將有線程問題,因爲你可以看到你可以覆蓋隊列上的同一位置有兩個線程,因爲後對方已經做了同樣的一個是寫作,不過這並沒有已經能夠增加指針了。

考慮到這一點,你有幾個選擇,如上所述,使用Queue.Synchronized()或更簡單的方法鎖定Enqueue()方法,但對性能影響更大,訪問隊列時鎖定私有屬性(因爲你用Queue做的任何事情都不是線程安全的):

Private ReadOnly Property MyQueue() as Queue 
Get 
    SyncLock (m_myQueueLock) 
     Return m_myQueue 
    EndSyncLock 
End Get 
End Property 

希望這有助於!