Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mono hangs when trying to open a StreamWriter to a named pipe

Tags:

c#

linux

pipe

mono

The program I'm writing is using FIFO pipes in linux for inter-process communication. It's rather hacky at best, but regardless I'm having issues.

        if (!File.Exists(Path.GetTempPath() + "gminput.pipe"))
        {
            ProcessStartInfo startInfo = new ProcessStartInfo() { FileName = "/usr/bin/mkfifo", Arguments = Path.GetTempPath() + "gminput.pipe", };
            Process proc = new Process() { StartInfo = startInfo, };
            proc.Start();
            proc.WaitForExit();
        }
        if (!File.Exists(Path.GetTempPath() + "gmoutput.pipe"))
        {
            ProcessStartInfo startInfo = new ProcessStartInfo() { FileName = "/usr/bin/mkfifo", Arguments = Path.GetTempPath() + "gmoutput.pipe", };
            Process proc = new Process() { StartInfo = startInfo, };
            proc.Start();
            proc.WaitForExit();
        }

        using (StreamWriter outputPipe = new StreamWriter(Path.GetTempPath() + "gmoutput.pipe"))
        using (StreamReader inputPipe = new StreamReader(Path.GetTempPath() + "gminput.pipe"))
        {
            Console.WriteLine("This code is never reached!");
        }

All I'm doing is checking if the pipe already exists, and if not, call mkfifo to create it. This part seems to work fine, the named pipes are created correctly. Whenever I try to open them (either with the StreamWriter, StreamReader, or both), the program just hangs. No errors or anything. It hangs in the debugger too.

The best part is...it used to work. I had the inter-process communication working and then it just inexplicably stopped. I commented out everything except what you see here, restarted my system, recreated the pipes, etc, to no avail. What gives? Is there something wrong with my code or is something else on the system interfering?

like image 219
DWilliams Avatar asked May 08 '17 01:05

DWilliams


1 Answers

That's by design. Try the following: open 2 bash terminals, create a pipe, then read it in one of the terminals and write to it in the other. For example

>mkfifo test.fifo
>echo "test" > test.fifo

>cat test.fifo

You'll see that no matter the order, each side blocks waiting for the other side.

Process 1's input pipe is Process 2's output pipe and visa versa. If both processes use the same code to access the pipe, process 1 reads its input pipe and blocks waiting for process 2 to write something. Process 2 also reads it's input pipe and waits for process 1 to write, but process 1 is waiting and hasn't even opened the other pipe. Gridlock.

One way to get around this is to run the reader or the writer in a separate thread. That way process 1 & 2 open both pipes and the gridlock is resolved.

The other option, is to open the pipe asynchronously. My C# is rusty, but there are plenty of examples on stackoverflow:

How to do a non-waiting write on a named pipe (c#)?

NamedPipeServerStream in Mono

Basically pass a NamedPipeServerStream to the reader/writer.

I suspect it worked before because P1 opened Reader, then Writer, while P2 opened Writer, then Reader thus unblocking P1.

like image 153
ventsyv Avatar answered Oct 21 '22 04:10

ventsyv