【问题标题】:Does BeginSend<IList<ArraySegment....) perform atomic send of all the ArraySegments?BeginSend<IList<ArraySegment....) 是否执行所有 ArraySegment 的原子发送?
【发布时间】:2011-07-04 08:36:54
【问题描述】:

.NET 中的 Socket 类公开了以下方法:

Socket.BeginSend Method (IList<ArraySegment<Byte>>, SocketFlags, AsyncCallback, Object)

我有一个 BufferManager 类,它返回指定大小为 2kB 的 ArraySegment&lt;byte&gt;。现在我有一条消息要发送,假设它有 10kB 大,所以我可以使用 5 个预分配的缓冲区来存储这条消息并调用Socket.BeginSend(IList&lt;ArraySegment&gt;&gt;...)。这条消息会自动发送吗,就像我只使用 byte[] 时一样(即多个并行 BeginSend 操作不会在远程站点上混合消息)?

编辑:澄清一下——我正在使用 TCP/IP 套接字,我的程序同时从多个线程调用 BeginSend。 假设我们有两个数组段列表:
L1: a1 a2 a3
L2: b1 b2 b3
现在我同时从两个线程调用 BeginSend(L1...) 和 BeginSend (L2...)。我想知道这两个列表是否不会在远程端混合,我不会读到类似的内容:a1 b1 b2 a2 b3 a3。

【问题讨论】:

  • “原子”是什么意思?顺序将得到保证,但我不认为这是线程安全的。
  • 套接字对“原子”的概念一无所知。他们是非常低级的。如果您需要这样的保证,那么您需要提高抽象级别并使用 WCF 之类的东西。
  • @John Saunders 我知道套接字没有原子性的概念,但是当我调用 Send(byte[]) 时,我确信发送的字节将“不间断”地到达消息和正确的顺序(尽管它们可能以多个 TCP 数据包和另一个数据包的形式出现,具体取决于 MTA 设置)。我只想知道在使用 BeginSend (IList) 时是否可以指望相同的行为
  • @Henk Holterman 所以顺序是有保证的——当我调用两个 BeginSend 时,我可以确定远程端不会收到假设:来自第一个 BeginSend 的两个元素,另一个元素的所有元素一个,以及第一个列表中的其余元素?
  • @paszczi 所以让我们进一步分解你的问题;如果您可以保证原子性,这将意味着第一个写入的线程必须如何进入底层套接字的队列,在有机会时抓住套接字,然后坚持在等待其缓冲区刷新足够时间的同时发送所有字节序列。这样的机制当然不是我希望看到在像 Socket 这样低级的东西中实现的东西。

标签: c# .net sockets


【解决方案1】:

BufferManager 所做的只是维护一组固定的内存块供您使用。 BufferManager 对字节的并发性没有影响,也不影响它们的使用方式。来自 MSDN 文档:

您可以使用 BufferManager 类来管理缓冲池。池及其缓冲区在您实例化此类时创建,并在缓冲池被垃圾回收回收时销毁。每次需要使用缓冲区时,从池中取出一个,使用它,完成后将其返回池中。这个过程比每次需要使用缓冲区时创建和销毁缓冲区要快得多。

BufferManager 只是一种避免调用 new[] 然后等待 GC 销毁块的便捷方式。当您完成发送这些块时,请确保您调用 BlockManager.ReturnBuffer,否则这些字节将无法用于未来的消息,并且会一直持续到您的 BufferManager 本身被 GC'd。如果它将使用实时 BufferManager,并且您正在使用这些缓冲区发送大量消息,那么您可能会泄漏大量内存。

【讨论】:

  • 我的问题不是关于 BufferManager 的线程安全,我提供了这条信息来创建一些上下文。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-11
  • 2013-03-12
  • 1970-01-01
相关资源
最近更新 更多