通过TextWriter进行通信 - >的TextReader

时间:2009-08-20 15:04:32

标签: c# .net

进行进程间通信的一种方法是通过进程之间的(命名)管道。

我希望在两个线程之间实现相同的“队列”式通信。生产者应该编写一个文本库命令(使用TextWriter或输出Stream)。 消费者应该从TextReader中读取。因为,你考虑一下,OutputStream / -Writer是InputStream / -Reader硬币的另一面。因此,使用Writer来为Reader填充数据,理论上应该很容易。

(这里的标准方法是在线程之间有一个队列。但是我希望使用TextReader和TextWriter,因为我已经有了前端和后端的代码。这样通过连接控制台就可以轻松调试。在/ Console.Out到生产者/消费者。)

我认为将作者连接到阅读器真的很容易,但我找不到如何做到这一点。

我可以自己写一个这样的连接,但感觉它“应该”已经存在。

有什么想法吗?

干杯 雷夫

2 个答案:

答案 0 :(得分:2)

我不鼓励使用流和TextWriter / TextReader作为线程之间的有效通信方式。您需要为每个“队列”设置一个流,并确保完全写入或读取有效数据,您需要为每次写入或读取操作锁定该流。一个更好的解决方案可能是这样的:

设置一个类型字符串的队列,以及一对手动重置动作。一般的想法是使用线程信令允许两个线程进行通信而无需锁定。

public static class ThreadTest
{
    public void Main()
    {
        long exit = 0;

        Queue<string> messages = new Queue<string>();
        ManualResetEvent signal1 = new ManualResetEvent();
        ManualResetEvent signal2 = new ManualResetEvent();

        signal2.Set();

        Thread writer = new Thread(() =>
        {
            while (exit == 0)
            {
                string value = Console.ReadLine();
                if (value == "exit")
                {
                    Interlocked.Exchange(ref exit, 1);
                }
                else
                {
                    messages.Enqueue(value);
                    Console.WriteLine("Written: " + value);
                    signal1.Set();
                }

                signal2.WaitOne();
            }
        });

        Thread reader = new Thread(() =>
        {
            while (exit == 0)
            {
                signal1.WaitOne();
                signal2.Reset();

                value = messages.Dequeue();
                Console.WriteLine("Read: " + value);

                signal2.Set();
                signal1.Reset();
            }
        });

        reader.Start();
        writer.Start();
    }
}

答案 1 :(得分:1)

我放弃了找到“现成的”解决方案。我写了自己的。 一个新的类ThroughputStream,它的Write-end接收数据,通过线程安全队列发送到Read-end,使用接收到的数据块来读取。

namespace My.IO
{
    public class ThrouputStream 
    {
        private InputStreamClass inputStream;
        private OutputStreamClass outputStream;

        private Queue<byte[]> queue = new Queue<byte[]>();
        private System.Threading.EventWaitHandle queueEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.AutoReset);

        public ThrouputStream()
        {
            inputStream = new InputStreamClass(this);
            outputStream = new OutputStreamClass(this);
        }

        public Stream InputStream
        {
            get { return inputStream; }
        }

        public Stream OutputStream
        {
            get { return outputStream; }
        }

        private class InputStreamClass : Stream
        {
            private readonly Queue<byte[]> queue;
            private readonly ThrouputStream parent;
            private byte[] currentBlock = null;
            private int currentBlockPos = 0;
            private Boolean closed = false;
            private int readTimeoutMs = System.Threading.Timeout.Infinite;

            public InputStreamClass(ThrouputStream parent)
            {

                this.parent = parent;
                this.queue = parent.queue;
            }

            public override bool CanRead
            {
                get { return true; }
            }

            public override bool CanSeek
            {
                get { return false; }
            }

            public override bool CanWrite
            {
                get { return false; }
            }

            public override void Flush()
            {
                // Do nothing, always flushes.
            }

            public override long Length
            {
                get { throw new NotSupportedException(); }
            }

            public override long Position
            {
                get
                {
                    throw new NotSupportedException();
                }
                set
                {
                    throw new NotSupportedException();
                }
            }

            public override bool CanTimeout
            {
                get
                {
                    return true;
                }
            }

            public override int ReadTimeout
            {
                get
                {
                    return readTimeoutMs;
                }
                set
                {
                    readTimeoutMs = value;
                }
            }

            public override int Read(byte[] buffer, int offset, int count)
            {
                if (currentBlock == null)
                {
                    int queueCount;
                    lock (queue)
                    {
                        queueCount = queue.Count;
                        if ( queueCount > 0 )
                            currentBlock = queue.Dequeue();
                    }

                    if (currentBlock == null && !parent.outputStream.IsClosed )
                    {
                        parent.queueEvent.WaitOne(readTimeoutMs);

                        lock (queue)
                        {
                            if (queue.Count == 0)
                                return 0;

                            currentBlock = queue.Dequeue();
                        }
                    }

                    currentBlockPos = 0;
                }

                if (currentBlock == null)
                    return 0;

                int read = Math.Min(count, currentBlock.Length - currentBlockPos);
                Array.Copy(currentBlock, currentBlockPos, buffer, offset, read);
                currentBlockPos += read;
                if (currentBlockPos == currentBlock.Length)
                {
                    // did read whole block
                    currentBlockPos = 0;
                    currentBlock = null;
                }

                return read;
            }

            public override long Seek(long offset, SeekOrigin origin)
            {
                throw new NotImplementedException();
            }

            public override void SetLength(long value)
            {
                throw new NotImplementedException();
            }

            public override void Write(byte[] buffer, int offset, int count)
            {
                throw new NotImplementedException();
            }

            public override void Close()
            {
                this.closed = true;
                base.Close();
            }
        }

        private class OutputStreamClass : Stream
        {
            private bool isClosed = false;

            private readonly Queue<byte[]> queue;
            private readonly ThrouputStream parent;

            public OutputStreamClass(ThrouputStream parent)
            {
                this.parent = parent;
                this.queue = parent.queue;
            }

            public override bool CanRead
            {
                get { return false; }
            }

            public override bool CanSeek
            {
                get { return false; }
            }

            public override bool CanWrite
            {
                get { return true; }
            }

            public override void Flush()
            {
                // always flush
            }

            public override long Length
            {
                get { throw new NotSupportedException(); }
            }

            public override long Position
            {
                get
                {
                    throw new NotSupportedException();
                }
                set
                {
                    throw new NotSupportedException();
                }
            }

            public override int Read(byte[] buffer, int offset, int count)
            {
                throw new NotSupportedException();
            }

            public override long Seek(long offset, SeekOrigin origin)
            {
                throw new NotSupportedException();
            }

            public override void SetLength(long value)
            {
                throw new NotSupportedException();
            }

            public override void Write(byte[] buffer, int offset, int count)
            {
                byte[] copy = new byte[count];
                Array.Copy(buffer, offset, copy, 0, count);
                lock (queue)
                {
                    queue.Enqueue(copy);
                    try
                    {
                        parent.queueEvent.Set();
                    }
                    catch (Exception)
                    { }
                }
            }

            public override void Close()
            {
                this.isClosed = true;
                base.Close();

                // Signal event, to stop waiting consumer
                try
                {
                    parent.queueEvent.Set();
                }
                catch (Exception)
                { }
            }

            public bool IsClosed
            {
                get { return isClosed; }
            }
        }

    }
}