异步写入套接字线程是否安全?

时间:2012-04-13 18:47:18

标签: c# sockets asynchronous io thread-safety

考虑Socket.BeginSend()方法。如果两个线程池线程同时调用此方法,它们各自的消息是否最终会相互混合,或者socket类是否会阻止它发生?

2 个答案:

答案 0 :(得分:14)

.NET Socket实例不是线程安全的,因为同时调用某些方法(相同或不同的方法)可能会导致状态不一致。但是, BeginSend()BeginReceive()方法相对于自身是线程安全的

对每个(或两者)进行多次未完成的调用是安全的。

BeginReceive()的情况下,当数据在调用的顺序中可用时,它们将被服务。例如,如果您的处理过长但希望尽快发生其他接收,则此功能非常有用。当然,在这种情况下,您可能会让代码同时处理多个收据,您可能需要自己的同步逻辑来保护您的应用程序状态。

BeginSend()的情况下,每次调用都会尝试将发送的数据推送到套接字缓冲区,一旦被接受,就会调用你的回调(你将调用EndSend() })。如果任何调用没有足够的缓冲区空间,它将阻塞。

注意:不要假设默认的8k缓冲区意味着“我可以使用正好8k的数据快速调用BeginSend(),然后它将阻止”,如下所示:

  1. 8K是“名义大小”的数字,缓冲区可能会缩小并稍微增长

  2. 当您排队等待8K的呼叫时,将在网络上发送数据,减少8K的排队数据

  3. 一般来说:

    • 如果你在一个帖子中多次拨打BeginSend(),你可以确信这些发送将按照他们被叫的顺序离开机器。

    • 如果从多个线程中调用BeginSend(),则无法保证顺序,除非您使用其他阻塞机制强制实际调用以某种特定顺序发生。但是,每次调用都会在一个连续的网络字节流中正确发送数据。

答案 1 :(得分:7)

我发现了一个熟悉的post on the MSDN forum似乎回答了你的问题。

  
      
  1. 您可以同时排队多个BeginSends。您无需锁定
  2.   

编辑:

更有趣的信息:

如果向下滚动Remark section of the MSDN doc BeginSend()中的一些内容,您会发现可能与您相关的回调方法的有趣用法。

  

[...]如果您希望在调用BeginSend方法后阻止原始线程,请使用WaitHandle.WaitOne方法。 [...]