从一个线程多次调用NetworkStream.BeginWrite是安全的吗?

时间:2015-06-04 06:25:57

标签: c# unity3d mono tcpclient

我正在Unity3D游戏中实现一个TCP客户端,我想知道在不等到上一次调用完成写入之前调用NetworkStream.BeginWrite是否真的安全。

根据我在阅读文档时的理解,它是安全的,直到我不在不同的线程中执行并发的BeginWrite调用(并且Unity只有一个用于游戏主循环的线程)。

对于我的阅读,我在与异步回调建立连接之后立即调用BeginRead,我在其中读取来自TcpClient.GetStream()的传入数据,将其放入带锁定的独立MemoryStream(readMemoryStream),然后再次运行BeginRead。除此之外,在我的Update()函数中(在主游戏线程中)我检查readMemoryStream中的新数据,检查实体消息并解压缩(当然使用相同的锁(readMemoryStream))并对其执行操作基于来自服务器的消息的游戏对象。

这种方法可行吗?不会有BeginRead干扰BeginWrite吗? 我再次使用回调线程来读取要写入的数据和主线程。

1 个答案:

答案 0 :(得分:2)

只要没有两个线程同时调用BeginWrite() ,一切都很好。在早期调用完成之前,相同的线程甚至其他线程可以连续调用BeginWrite()

请注意,完成回调可能无序执行;如果以这种方式实现它并且完成回调的执行顺序很重要,则由您来跟踪哪个异步操作是哪个。当然,对于写入套接字,这通常无关紧要,因为除了调用EndWrite()之外,您在完成回调中可能没有任何操作。

读取和写入套接字是完全独立的操作。套接字是全双工的,可以安全地处理同一套接字上的并发挂起读写操作。


您没有问过,但是像BeginWrite()一样,您也可以多次调用BeginRead()而无需先前的操作完成。同样,与BeginWrite()一样,由您来跟踪操作的正确顺序,以便在为每个操作执行完成回调时,您知道接收到的数据应该在哪个顺序。

请注意,由于完成的顺序对于读取操作(写入操作通常不是这种情况)至关重要,因此除了最大规模的实现之外的所有实现从不与给定套接字上的读取操作重叠。对于给定的套接字,代码要简单得多,一次只进行一次读取操作。


最后一点需要注意:请注意您的缓冲区在I / O操作期间被固定。由于碎片,太多未完成的I / O操作可能会干扰堆的有效管理。这在客户端实现中不太可能是一个问题,但是大规模的服务器实现应该考虑到这一点(例如,通过分配大缓冲区,使它们来自LOH,无论如何总是固定的。)