2012-02-20 127 views
3

我有我的Sender類兩種方法:在兩個併發的NetworkStream.BeginWrite調用中會發生什麼?

public void SendMessage(OutgoingMessage msg) 
{ 
    try 
    { 
     stream.BeginWrite(msg.TcpData, 0, 16, messageSentCallback, msg); 
    } 
    catch 
    { 
     // ... 
    } 
} 

private void messageSentCallback(IAsyncResult result) 
{ 
    stream.EndWrite(result); 

    if (result.IsCompleted) 
     onDataSent(result.AsyncState as OutgoingMessage); 
} 

程序可以調用(如果他們有到發件人的訪問)SendMessage()方法的其他部分。由於該程序在多線程環境中工作,多線程可以訪問發件人對象。

我有2個問題:

Q1)將使得向SendMessage方法兩個同時呼叫能夠弄亂TCP通信(通過填充具有混合數據的TCP傳出緩衝液)?

Q2)將封閉的stream.BeginWrite()調用打入lock { }解決這個問題?

據我所知,調用BeginWrite只是將數據存儲到TCP輸出緩衝區中。是對的嗎?

+0

這不會出錯,第二次調用引發異常。鎖定BeginWrite調用沒有修復,只需要幾微秒。您需要修復代碼中的邏輯錯誤。 – 2012-02-20 15:39:54

+0

您是否認爲所需的場景是在調用stream.EndWrite之前不允許另一個BeginWrite?這會起作用嗎?是的,鎖會阻止其他線程調用BeginWrite,但這並不意味着套接字(或其緩衝區)處於可以再次寫入的狀態(直到調用EndWrite)。那是對的嗎? – 2012-02-21 06:23:46

回答

3

是,鎖在一個時間調用BeginWrite需要避免問題。但是,我會切換到另一種方法,既要解決併發問題,又要讓線程交互更容易推理。

您可能有一個共享隊列,其中幾個線程將請求寫入流中。單線程然後從隊列讀取請求並進行寫入操作。現在瞭解發生的事情要容易得多,而且您不必擔心同步寫入操作。您可以使用其中一個併發集合,如ConcurrentQueue

+0

是的,我知道這種方法,但是,在這種情況下,需要額外的線程管理 - 什麼時候啓動它,發送到TCP的頻率以及在發生錯誤時應該怎麼做。但這絕對是更好的方式。 – 2012-02-21 06:19:10

2

MSDN說

只要沒有爲寫操作一個唯一的線程和讀操作的一個 唯一的線程,會出現讀取之間沒有 交叉干擾和寫線程,沒有 同步是必需的。

這意味着,如果你有一個以上的線程發送數據,那麼你應該使用lock,使只有確保一個線程,以不受任何干擾發送數據

1

如果您希望儘量減少阻塞並保持多個寫入器線程的高併發性,我會推薦使用Socket.SendAsync,它接受SocketAsyncEventArgs

您可以預先分配多個用作編寫器的SocketAsyncEventArgs(與其關聯的緩衝區空間),在這種情況下,而不是鎖定您將有一個SemaphoreSlim,這將允許一些'同時'在協議棧下同步。

  • Here是一個可以讓你開始(也表明池爲您的緩衝區。)
  • Here是一個CodeProject上的文章也證明了其使用代碼庫的樣本。

祝你好運!