Sequential asynchronous reads using Stream.BeginRead

ε祈祈猫儿з 提交于 2019-12-10 20:07:32

问题


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?


回答1:


Here you might end up with multiple threads calling BeginRead on the same instance of resource (baseStream). As per MSDN, the "EndRead must be called exactly once for every call to BeginRead. Failing to end a read process before beginning another read can cause undesirable behavior such as deadlock." In you case, I recon a trouble 'if Thread B is on Seek (on baseStream) while Thread A in the middle of executing their EndRead(callback)'.

Due to the nature of requirement, you are better off with wrapping multi-threaded access with synchronous I/O. This means, the current implementation can be amended with synchronous I/O instead of asynchronous I/O. Also, you may want to consider informing queuing threads about the completion of former threads using Monitor.WaitOne (baseStream) and Monitor.Pulse(baseStream) or Monitor.PulseAll(baseStream).

Alternately, I would like to throw another idea of Memory-Mapped file for segmented style.




回答2:


In the given code snippet you'll read multiple times from the same position. Move the position update to the BeginRead function. Apart from that you are honoring the contract of the FileStream class by never concurrently calling its methods.



来源:https://stackoverflow.com/questions/22779526/sequential-asynchronous-reads-using-stream-beginread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!