2012-02-20 129 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上的文章也证明了其使用代码库的样本。

祝你好运!