在两个并发的NetworkStream.BeginWrite调用中会发生什么?

时间:2012-02-20 15:10:04

标签: c# multithreading networking concurrency tcp

我的Sender课程有两种方法:

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()方法。由于程序在多线程环境中工作,因此多个线程可以访问Sender对象。

我有 2个问题:

Q1)SendMessage方法进行两次并发调用是否能够搞乱TCP通信(通过使用混合数据填充TCP传出缓冲区)?

Q2)stream.BeginWrite()电话括在lock { }中解决此问题?

据我所知,对BeginWrite的调用只是将数据存储到TCP传出缓冲区中。是吗?

3 个答案:

答案 0 :(得分:3)

是的,需要锁定才能避免问题。但是,我会切换到另一种方法,既解决并发问题,又使线程交互更容易推理。

您可以拥有一个共享队列,其中多个线程将需要写入的请求写入流。然后,单个线程从队列中读取请求并进行写入操作。现在,更容易理解正在发生的事情,您不必担心同步写入。您可以使用其中一个并发集合,例如ConcurrentQueue

答案 1 :(得分:2)

MSDN说

  

只要有一个唯一的写操作线程和一个   用于读取操作的唯一线程,将没有   读写线程之间的交叉干扰没有   同步是必需的。

这意味着如果您有多个线程发送数据,那么您应该使用lock来确保一次只有一个线程调用BeginWrite以便发送数据而不会受到任何干扰

答案 2 :(得分:1)

如果您希望最小化阻塞并使用多个编写器线程保持高并发性,我建议使用接受Socket.SendAsyncSocketAsyncEventArgs

你可以预先分配一些用作编写器的SocketAsyncEventArgs(及其相关的缓冲区空间),在这种情况下,你可以拥有SemaphoreSlim而不是锁定,这将允许一些“同时”写入推送同步降低协议栈。

  • Here是一个可以帮助您入门的代码库示例(还演示了缓冲池的汇集。)
  • Here是一个代码项目文章,也展示了它的用法。
祝你好运!