Stream.Write 是线程安全的吗?
我正在为旧版 RPC 实现开发客户端/服务器库,但遇到了客户端在等待接收 RPC 请求消息的响应消息时有时会挂起的问题。事实证明,真正的问题出在我的消息框架代码中(当从底层 NetworkStream 读取数据时,我没有正确处理消息边界),但这也让我对我用来实现消息框架的代码产生了怀疑。通过网络发送数据,特别是在 RPC 服务器根据客户端 RPC 请求向客户端发送大量数据的情况下。
我的发送代码使用 BinaryWriter
将完整的“消息”写入底层 NetworkStream
。 RPC 协议还实现了心跳算法,其中 RPC 服务器每 15 秒发送一次 PING 消息。 ping 是由单独的线程发出的,因此,至少在理论上,可以在服务器将大量响应流式传输回客户端时发送 ping。
假设我有一个 Send
方法,如下所示,其中 stream
是 NetworkStream
:
public void Send(Message message)
{
//Write the message to a temporary stream so we can send it all-at-once
MemoryStream tempStream = new MemoryStream();
message.WriteToStream(tempStream);
//Write the serialized message to the stream.
//The BinaryWriter is a little redundant in this
//simplified example, but here because
//the production code uses it.
byte[] data = tempStream.ToArray();
BinaryWriter bw = new BinaryWriter(stream);
bw.Write(data, 0, data.Length);
bw.Flush();
}
所以我的问题是,是对 的调用bw.Write
(并且隐含对底层 Stream
的 Write
方法的调用)是原子的吗?也就是说,如果发送线程上仍在进行冗长的Write
,并且心跳线程启动并发送 PING 消息,则该线程是否会阻塞,直到原始Write
调用完成,或者我是否必须向 Send
方法添加显式同步,以防止两个 Send
调用破坏流?
I'm working on a client/server library for a legacy RPC implementation and was running into issues where the client would sometimes hang when waiting to a receive a response message to an RPC request message. It turns out the real problem was in my message framing code (I wasn't handling message boundaries correctly when reading data off the underlying NetworkStream
), but it also made me suspicious of the code I was using to send data across the network, specifically in the case where the RPC server sends a large amount of data to a client as the result of a client RPC request.
My send code uses a BinaryWriter
to write a complete "message" to the underlying NetworkStream
. The RPC protocol also implements a heartbeat algorithm, where the RPC server sends out PING messages every 15 seconds. The pings are sent out by a separate thread, so, at least in theory, a ping can be sent while the server is in the middle of streaming a large response back to a client.
Suppose I have a Send
method as follows, where stream
is a NetworkStream
:
public void Send(Message message)
{
//Write the message to a temporary stream so we can send it all-at-once
MemoryStream tempStream = new MemoryStream();
message.WriteToStream(tempStream);
//Write the serialized message to the stream.
//The BinaryWriter is a little redundant in this
//simplified example, but here because
//the production code uses it.
byte[] data = tempStream.ToArray();
BinaryWriter bw = new BinaryWriter(stream);
bw.Write(data, 0, data.Length);
bw.Flush();
}
So the question I have is, is the call to bw.Write
(and by implication the call to the underlying Stream
's Write
method) atomic? That is, if a lengthy Write
is still in progress on the sending thread, and the heartbeat thread kicks in and sends a PING message, will that thread block until the original Write
call finishes, or do I have to add explicit synchronization to the Send
method to prevent the two Send
calls from clobbering the stream?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
来自 Stream 类,所以否
From Stream Class, so no it is not guaranteed.
它没有记录为原子的。我不会假设它是,并且肯定会将这些东西包裹在自定义锁定机制中。基本上整个 Send 方法几乎都需要锁。
It is not documented as atomic. I would not assume it is and definitely would wrap that stuff around a custom locking mechanism. Basically the whole Send method pretty much asks for a lock.
为了确定,您应该将编写器锁定在两个线程中。公平地说,作者不是线程安全的。
检查 MSDN 中的“Monitor”和“Mutex”。
You should lock the writer in both threads to be sure. Afair the writer is not thread safe.
Check MSDN for "Monitor" and "Mutex".