问题
I've written the following function to implement a timeout feature using NetworkStream
's asynchronous read functions (BeginRead
and EndRead
). It works fine until I comment out the line Trace.WriteLine("bytesRead: " + bytesRead);
. Why?
private int SynchronousRead(byte[] buffer, int count)
{
int bytesRead = 0;
bool success = false;
IAsyncResult result = null;
result = _stream.BeginRead(
buffer, 0, count,
delegate(IAsyncResult r)
{
bytesRead = _stream.EndRead(r);
},
null);
success = result.AsyncWaitHandle.WaitOne(_ioTmeoutInMilliseconds, false);
if (!success)
{
throw new TimeoutException("Could not read in the specfied timeout.");
}
//If I remove this line, bytesRead is always 0
Trace.WriteLine("bytesRead: " + bytesRead);
return bytesRead;
}
Just in case you're wondering, I have to do this because I will eventually need to target the .Net Compact Framework 3.5 and it doesn't support the NetworkStream.ReadTimeout
and NetworkStream.WriteTimeout
properties.
回答1:
An interesting threading bug. The bytesRead variable is assigned after the wait handle is signaled. Two things can go wrong: the method returns before the assignment is made. Or the thread reads a stale value since their is no memory barrier past the WaitOne() call. The Trace statement fixes the problem because it delays the main thread long enough to allow the variable to be written. And it has an internal lock that ensures the cache is coherent.
You'll need an additional AutoResetEvent that signals that bytesRead variable was written.
回答2:
Besides the memory barrier problem in you code (As Hans also pointed), If i were you i'd use Reactive Extension instead that would make this code segment in just three lines of code. If you have time, I'd strongly suggest you to use Rx instead.
Cheers
来源:https://stackoverflow.com/questions/7696856/implementing-a-timeout-with-networkstream-beginread-and-networkstream-endread