12

考虑Socket.BeginSend()方法。如果两个线程池线程同时调用此方法,它们各自的消息最终会相互混合还是套接字类会阻止这种情况发生?

4

2 回答 2

16

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

对每个(或两者)都有多个未完成的调用是安全的。

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

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

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

  1. 8K 是一个“标称大小”的数字,缓冲区可能会缩小并有所增长

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

一般来说:

  • 如果您BeginSend()在一个线程中多次调用,您可以确保发送将按照它们被调用的顺序离开机器。

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

于 2012-04-20T23:28:59.110 回答
7

在 MSDN 论坛上找到了一个类似的帖子,似乎可以回答您的问题。

  1. 您可以同时对多个 BeginSend 进行排队。你不需要锁定

编辑:

更有趣的信息:

如果您在 MSDN 文档 BeginSend() 的 Remark 部分向下滚动一点,您会发现可能与您相关的回调方法的有趣用法。

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

于 2012-04-13T18:58:53.583 回答