【问题标题】:MemoryStream with wait till there is something to readMemoryStream 等到有东西要读
【发布时间】:2014-12-03 08:15:30
【问题描述】:

这是一个非常简单的问题,但如果不与某人交谈,我似乎无法弄清楚。

我需要一个像 MemoryStream 这样的流,它会在读取时异步阻塞,直到有要读取的内容或超时。

更新: 好的。我已经放弃了,自己写了Wrapper类,但是EndRead总是返回0。请看下面的代码。 (不提供面向任务的解决方案。)

    public class BlockingMemoryStream : MemoryStream
    {
        ManualResetEventSlim isReadReady = new ManualResetEventSlim(false);

        public override void Write(byte[] buffer, int offset, int count)
        {
            base.Write(buffer, offset, count);
            //base.Position = offset; //I do not know if I need this!!!!
            isReadReady.Set();
        }

        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            IAsyncResult result = base.BeginRead(buffer, offset, count, callback, state);
            return result;
        }

        public override int EndRead(IAsyncResult asyncResult)
        {
            isReadReady.Wait(/*600000*/);
            int aa = base.EndRead(asyncResult);
            return aa;
        }
    }

【问题讨论】:

  • 上下文不清楚或不明显。它将如何写入?
  • 请查看 C.Evenhuis 代码。那就是我要避免的代码。
  • 如果您真的只想要一个涉及 .NET 本身现有实现的答案,我认为您不会得到这个答案。一个简单的启用超时的Stream 包装器可以在没有太多麻烦的情况下实现(尽管有当前的答案),但我想如果你只对.NET 中已经存在的东西感兴趣,那么提供它是没有意义的。

标签: c# asynchronous stream


【解决方案1】:

尝试这样的事情,它所做的只是循环并等待直到有要读取的对象。

    private static readonly MemoryStream _reader;
    private static object _data;

    static Program()
    {
        _reader = new MemoryStream();
    }

    private static void Main(string[] args)
    {
        Task.Run(async delegate()
        {
            while (true)
            {
                if (_data == null)
                    await Task.Delay(1000); // so the cpu can have rest
                                            // you can lower the value of this
                else
                {
                    // read here
                    await Task.Delay(1000);
                }
            }
        });
    }

【讨论】:

    【解决方案2】:

    如果我理解正确,您想要一个您写入的流,另一个线程从中读取。您可以自己滚动,即:

    public sealed class MyStream : Stream
    {
        private readonly MemoryStream underlyingStream = new MemoryStream();
        private readonly AutoResetEvent waitHandle = new AutoResetEvent(false);
    
        public int Timeout { get; set; }
    
        public MyStream()
        {
            Timeout = 5000;
        }
    
        public override void Write(byte[] buffer, int offset, int count)
        {
            // Write to the stream and notify any waiting threads
            underlyingStream.Write(buffer, offset, count);
            waitHandle.Set();
        }
    
        public override int Read(byte[] buffer, int offset, int count)
        {
            int bytes;
            while ((bytes = underlyingStream.Read(buffer, offset, count)) == 0)
            {
                // 0 bytes read (end of stream), wait Timeout ms for someone to write
                if (!waitHandle.WaitOne(Timeout))
                {
                    throw new TimeoutException();
                }
            }
    
            return bytes;
        }
    
        // TODO other mandatory methods
    }
    

    我在没有测试的情况下编写了上面的示例,Stream 的实现是不完整的,它只是为您的解决方案显示了一个可能的方向。如果有多个线程来自它Read,则可能需要多个Timeout 才能完成。

    如果您不喜欢摆弄等待句柄,您也可以在 TCP 环回上使用套接字并使用 NetworkStream

    【讨论】:

    • 谢谢!我考虑过实现这一点,但我希望 C# 中已经内置了一些东西。 NetworkStream 不好 - 它需要太多的虚拟变量。
    • 这个答案根本上是错误的,即使 OP 愿意接受非内置实现:当 Read() 操作返回 0 字节时,这表示 Stream 的结束。无论您等待多长时间,此时都不会再有任何字节了。
    • @PeterDuniho 我很欣赏你的评论,你是对的,它应该抛出TimeoutException,我会纠正我的答案。我认为这从根本上说没有错,我提供了自定义解决方案和内置解决方案的想法。
    猜你喜欢
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    相关资源
    最近更新 更多