我一直在尋找,但我似乎無法找到.NET如何處理競爭條件。
大部分情況並非如此。這取決於你。但是,從你的問題來看,你確實存在競爭狀況問題並不清楚。
你問這個文本,在the other answer:
如果套接字緩衝區中有足夠的數據,多個ReadAsyncs可以立即返回,而不在所有
首先做任何線程切換,要清楚:方法的名稱是ReceiveAsync()
,而不是ReadAsync()
。其他類,如StreamReader
和NetworkStream
有ReadAsync()
方法,這些方法與你的問題有關很少。現在,這澄清…
該報價是關於與相對的競賽狀況。該文本的作者警告您,如果您恰好在已準備好讀取數據的套接字上調用ReceiveAsync()
,數據將被同步讀取,並且SocketAsyncEventArgs.Completed
事件將在以後生成而不是。線程的責任是調用ReceiveAsync()
來處理讀取的數據。
所有這些都會發生在單個線程中。在這種情況下不會有任何競爭條件。
現在,讓我們考慮一下你的「快速作家,慢讀者」場景。可能發生的最糟糕的情況是,第一次讀取可能發生在任何線程中,但不會立即完成,但是當事件發生時,作者已經超過了讀者的速度。在這種情況下,由於處理Completed
事件的部分可能會再次調用ReceiveAsync()
,現在它將同步返回,因此IOCP線程池線程將在對ReceiveAsync()
的調用中循環。不需要新線程,因爲當前IOCP線程正在同步完成所有工作。但它確實阻止該線程處理其他 IOCP事件。
所有這一切將不過是說,如果你有一些其他插座的服務器處理,並且還需要調用ReceiveAsync()
,框架必須確保有一個在IOCP線程池可用於處理其他線程I/O。但是,這是一個完全不同的套接字,無論如何你都必須使用完全不同的緩衝區。
再次,沒有競爭條件。
現在,所有的說,如果你想獲得真正混淆,它是可以使用異步I/O的.NET Socket
API中(無論是與BeginReceive()
或ReceiveAsync()
甚至包裝插座在一個NetworkStream
和使用ReadAsync()
)以這樣的方式,你做有一個特定的套接字競爭條件。
我毫不猶豫地提到它,因爲沒有證據表明你的問題與你有關,也沒有你真的對這個級別的細節感興趣。添加這個解釋可能會混淆事物。但是,爲了完整性…
在任何給定的時間都可以在套接字上發出多個讀操作。這與雙緩衝或三緩衝視頻顯示有些類似(如果您熟悉該概念)。這個想法是,當新數據進來時你可能仍然在處理讀操作,並且在完成處理當前讀操作之前,已經有一個新的讀操作正在處理該數據,這將是更高效的。
這聽起來不錯,但由於方式的Windows調度線程的實踐,特別是不保證線程調度的一個特定的順序,如果你試圖實現你的代碼,這樣,您所創建的可能性您代碼將看到讀取操作不按順序完成。也就是說,如果您連續兩次調用ReceiveAsync()
兩次(當然有兩個不同的SocketAsyncEventArgs
對象和兩個不同的緩衝區),則可能會先使用第二個緩衝區調用您的Completed
事件處理程序。
這不是因爲讀取操作本身完成不按順序。他們不。因此重點在上面的「你的」。問題在於,當處理IO完成的IOCP線程以正確的順序運行時(因爲緩衝區按照您通過多次調用ReceiveAsync()
而提供的順序填充),第二個IOCP線程可以運行成爲可運行的第一個線程實際上預定由Windows運行。
這不難處理。您只需確保在發出讀取操作時跟蹤緩衝區序列,以便稍後以正確的順序重新組合緩衝區。所有可用的異步選項都提供了一種機制,讓您可以包含其他用戶狀態數據(例如SocketAsyncEventArgs.UserToken
),因此您可以使用它來跟蹤緩衝區的順序。
再次,這並不常見。對於大多數情況下,完全有序的實現,在完成當前讀取操作後,只發出新的讀取操作,就足夠了。如果您擔心讓多緩衝區讀取實現正確無誤,請不要打擾。堅持簡單的方法。
我相信鏈接的答案指的是連續多次調用ReadAsync的過程,而不是在同一個連接上同時調用多個ReadAsync。如果你這樣做,你不知道訂單數據收到了什麼(雖然我相信你仍然是安全的任何腐敗問題) –
@Damien_The_Unbeliever我相信每個套接字應該有一個ReadAsync。但我讀過的解釋似乎說一個ReadAsync可以旋轉多個IOCP線程。我不明白你爲什麼要這麼做。 –
嗯,我不能說明你讀過哪些內容,尤其是沒有鏈接。你爲什麼試圖深入挖掘?合同是你用特定目標字節數調用'ReadAsync',並且當其他一些數字(或者可能相同數量)的字節被傳送時你會得到通知。如果有任何線程問題需要處理(我不相信有),它們已經被框架處理。 –