Yasser Mohseni
Yasser Mohseni

Reputation: 463

Why Does Threading Break Named Pipes During Inter-Processing Communications?

I am trying to write a sample C# program for named pipe streaming. I create two executable files, one for server and another for client. Please check my code below. These two applications sometimes work correctly and sometimes client application closes without any reason or exception, resulting Pipe is broken exception in server application. I think, in this situation, these processes are not synchronized, specially when I put some delays in their code such as debug mode delays. Why is client process being suddenly closed when server is still waiting for PipeDrain (pipeServer.WaitForPipeDrain())?

I appreciate your help.

Server:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.IO;
using System.Threading;

namespace NamedPipeServer
{
    class NamedPipeServerClass
    {
        static void Main(string[] args)
        {
            NamedPipeServerStream pipeServer = new NamedPipeServerStream("namedPipe", PipeDirection.InOut, 4);
            StreamReader SR = new StreamReader(pipeServer);
            StreamWriter SW = new StreamWriter(pipeServer);
            pipeServer.WaitForConnection();
            string temp;
            try
            {
                SW.WriteLine("Waiting");
                SW.Flush();
                pipeServer.WaitForPipeDrain();
                temp = SR.ReadLine();
                Console.WriteLine(temp + '\n');

                SW.WriteLine("Hello");
                SW.Flush();
                pipeServer.WaitForPipeDrain();
                temp = SR.ReadLine();
                Console.WriteLine(temp + '\n');

                SW.WriteLine("How are you?");
                SW.Flush();
                pipeServer.WaitForPipeDrain();
                temp = SR.ReadLine();
                Console.WriteLine(temp + '\n');

                SW.WriteLine("GoodBye");
                SW.Flush();
                pipeServer.WaitForPipeDrain();
                temp = SR.ReadLine();
                Console.WriteLine(temp + '\n');
            }

            catch (Exception ex)
            {
                throw ex;
            }

            finally
            {
                pipeServer.WaitForPipeDrain();
                if (pipeServer.IsConnected)
                {
                    pipeServer.Disconnect();
                }
            }

            Console.WriteLine("Server: Press any key to exit...");
            Console.ReadLine();
        }
    }
}

Client:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
using System.IO;
using System.Threading;

namespace NamedPipeClient
{
    class NamedPipeClientClass
    {
        static NamedPipeClientStream pipeClient;
        static StreamReader SR;
        static StreamWriter SW;
        static Thread Conversation = new Thread(new ThreadStart(Con_function));
        static bool HandShake_Ok = false;

        static void Main(string[] args)
        {
            pipeClient = new NamedPipeClientStream(".", "namedPipe", PipeDirection.InOut, PipeOptions.None);
            if (pipeClient.IsConnected != true) 
            { 
                pipeClient.Connect(); 
            }
            SR = new StreamReader(pipeClient);
            SW = new StreamWriter(pipeClient);
            Conversation.Name = "ConversationThread";
            Conversation.IsBackground = true;
            Conversation.Start();
        }
        static void Con_function()
        {
            string temp;
            while (true)
            {
                try
                {
                    temp = SR.ReadLine();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                if (temp == "Waiting")
                {
                    HandShake_Ok = true;
                    try
                    {
                        SW.WriteLine("Welcome");
                        SW.Flush();
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
                else if (HandShake_Ok && temp == "Hello")
                {
                    try
                    {
                        SW.WriteLine("Hi");
                        SW.Flush();
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
                else if (HandShake_Ok && temp == "How are you?")
                {
                    try
                    {
                        SW.WriteLine("I am fine");
                        SW.Flush();
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
                else if (HandShake_Ok && temp == "GoodBye")
                {
                    try
                    {
                        HandShake_Ok = false;
                        SW.WriteLine("Good bye :)");
                        SW.Flush();
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
            }
        }
    }
}

Update: In the client the writings and readings into pipe are done in a thread, called Conversation. If I remove this thread and bring all writings and readings into Main function, the problem will be resolved. Why does thread have such an effect on inter-process pipeline communications?

Upvotes: 0

Views: 932

Answers (1)

Kyle R
Kyle R

Reputation: 61

I believe what you are experiencing here is since Conversation.IsBackground = true; the client application will NOT wait for the Conversation thread to complete before exiting

Try:

Conversation.Name = "ConversationThread";
Conversation.IsBackground = true;
Conversation.Start();
Conversation.Join();

The Conversation.Join(); blocks the calling thread from executing until the thread object terminates See Thread.Join Method & Thread.IsBackground Property on MSDN

Upvotes: 1

Related Questions