提问者:小点点

NamedPipeClientStream.Write块


我只是想理解C#中的管道。我有一个简单的LinqPad脚本:

void Main() =>  Program.Main(null);

// You can define other methods, fields, classes and namespaces here
    class Program
    {
        public static void Main(string[] args)
        {
            StartServer();
            Task.Delay(1000).Wait();

            //Client
            var client = new NamedPipeClientStream("PipesOfPiece");
            client.Connect();

            while (true)
            {
                string input = Guid.NewGuid().ToString();
                if (String.IsNullOrEmpty(input)) break;
                
                var someBuffer = new byte[4];
                client.Write(someBuffer, 0, someBuffer.Length);
                "Client 1st Write".Dump();
                
                client.Write(someBuffer, 0, someBuffer.Length);
                "Client 2nd Write".Dump();
                
                client.Read(someBuffer, 0, someBuffer.Length);
                "Client 1st Read".Dump();
            }
        }

        static void StartServer()
        {
            Task.Factory.StartNew(() =>
            {
                var server = new NamedPipeServerStream("PipesOfPiece");
                server.WaitForConnection();
                var someBuffer = new byte[4];
                while (true)
                {
                    server.Read(someBuffer, 0, someBuffer.Length);
                    "Server 1st Read".Dump();
                    server.Write(someBuffer, 0, someBuffer.Length);
                    "Server 1st Write".Dump();
                }
            });
        }
    }

如果运行上面的代码,将得到以下输出:

Client 1st Write
Server 1st Read

因此对client.write的第二次调用将永远阻塞。有人能解释一下为什么第二次调用write(在同一线程中)会导致管道阻塞吗?

THX


共1个答案

匿名用户

其根本原因是根据同步化上下文和线程切换阻塞问题。像这样做伙计:

public static async Task Main(string[] args)
{
        StartServer();
        await Task.Delay(1000);

        //Client
        var client = new NamedPipeClientStream("PipesOfPiece");
        await client.ConnectAsync();

        while (true)
        {
            string input = Guid.NewGuid().ToString();
            if (String.IsNullOrEmpty(input)) break;

            var someBuffer = new byte[4];
            await client.WriteAsync(someBuffer, 0, someBuffer.Length);
            Console.WriteLine("Client 1st Write");

            await client.WriteAsync(someBuffer, 0, someBuffer.Length);
            Console.WriteLine("Client 2nd Write");

            await client.ReadAsync(someBuffer, 0, someBuffer.Length);
            Console.WriteLine("Client 1st Read");

            //await Task.Delay(100);

        }
    }

    static void StartServer()
    {
        Task.Factory.StartNew(async () =>
        {
            var server = new NamedPipeServerStream("PipesOfPiece");
            await server.WaitForConnectionAsync();

            var someBuffer = new byte[4];
            while (true)
            {
                await server.ReadAsync(someBuffer, 0, someBuffer.Length);
                Console.WriteLine("Server 1st Read");
                await server.WriteAsync(someBuffer, 0, someBuffer.Length);
                Console.WriteLine("Server 1st Write");
            }
        });
    }