I'm writing a class that exposes a subsection of a stream for reading. Since data may be read from multiple different subsections at the same time, only one operation may be active at any one time.
I had the idea of locking the underlying stream before every operation. Is locking the stream around the BeginRead call sufficient to ensure that concurrent asynchronous reads from different positions in the underlying stream happen correctly?
public sealed class SubStream : Stream
{
// ...
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count,
AsyncCallback callback, object state)
{
lock (this.baseStream)
{
this.baseStream.Seek(this.offset + this.position, SeekOrigin.Begin);
return this.baseStream.BeginRead(buffer, offset, count,
callback, state);
}
}
public override int EndRead(IAsyncResult asyncResult)
{
int read;
lock (this.baseStream)
{
read = baseStream.EndRead(asyncResult);
this.position += read;
}
return read;
}
// Read() and ReadByte() also lock on this.baseStream (not shown).
// ...
}
For example, if thread A calls BeginRead, a lock on the base stream is acquired. Now thread B calls BeginRead and has to wait for the lock to be released. Thread A sets the position of the base stream and starts an asynchronous read operation. Then releases the lock. Thread B then acquires the lock and changes the position of the base stream and starts another asynchronous read operation. Then, sometime later, the asynchronous read from thread A completes. Can I be sure that this reads from the original position in the base stream? If not, how do I fix it?
ReaderWriterLockSlim? Especially theEnterWriteLockpart of it fits your description of forcing other threads to wait perfectly. - aevitasasyncandawait, in which case the lock would hold until your operation returns. In this case, I don't think it does. TheSemaphoreSlimclass has aWaitAsyncmethod which is probably interesting for you. - aevitasStream+SyncStreamin mscorlib, and there they also lock on the wrapped stream and also wrap the call toBeginReadin a lock. I may not own the object, but by locking on it I can be sure that other objects that lock on the stream (other instances of mySubStream, or an instance of .NET'sSyncStream) work correctly. Also, why wouldBeginReadthrow? When the lock is taken, the thread will block until it is released. Otherwise, the execution is no different from the same code without the lock. - Daniel A.A. Pelsmaeker