[fpc-pascal] Inter-process communication, a cautionary tale

Mark Morgan Lloyd markMLl.fpc-pascal at telemetry.co.uk
Wed Jul 18 17:01:16 CEST 2012


OBones wrote:
> Mark Morgan Lloyd wrote:
>> A couple of weeks ago, out of curiosity rather than necessity, I 
>> started looking at whether the library could be ported to Windows 
>> using MS-style named pipes. However I seem to have hit a snag since it 
>> appears that Windows can't both create a named pipe (for reading) and 
>> open the same named pipe (for writing) in the same process, something 
>> that gives unix sockets no problems at all.
> Could you show us some code here?
> And what return values do you get?
> I'm asking because I have distinct memories of doing just that a while 
> back without any issue.

I've certainly done it to communicate between separate processes, but 
the difference in the current case is that the first time the program is 
loaded I'm enqueueing its own parameters rather than passing them via an 
in-memory "shortcut"... works fine in unix and seemed like a good idea 
at the time :-) It's strange though just how many people on 
StackOverflow etc. say things like "using a named pipe to communicate 
inside a single process is utterly pointless", it's almost as though 
they're parroting some doctrine the origin of which is now lost.

Basically, what I was trying to do was this. In the main thread:

     fIpcPipe:= CreateNamedPipe(PChar(fIpcName), PIPE_ACCESS_INBOUND,
                         PIPE_TYPE_MESSAGE + PIPE_READMODE_MESSAGE,
                                 1, 0, 0, 1000, NIL (* @sa *) );

That works. Fire up a background reader thread, and make sure that the 
main thread doesn't proceed...

     fThread:= TSphinxThread.Create(false);
     while fThread.fSyncParam = DEADBEEF DO (* Until thread has called 
ConnectNamedPipe() *)
       Sleep(10);
     fThread.Suspend

..until after the Execute in the reader thread has done:

   fSyncParam := '';                     (* Let main process see that 
we've started *)
{$ifndef UNIX }
   IF NOT ConnectNamedPipe(Phix.Pipe, NIL) THEN
     EXIT;
{$endif UNIX  }
   WHILE NOT Terminated DO BEGIN

I'm keenly aware of the deprecated status of calling Suspend from 
outside the thread, but what I'm showing there is just one attempt from 
many.

Finally, once the main thread is confident that the background reader 
has got to the point of being connected to the named pipe:

   sendPipe:= CreateFile(PChar(fIpcName), GENERIC_WRITE, 
FILE_SHARE_WRITE + FILE_SHARE_READ,
                                 NIL, OPEN_EXISTING, 
FILE_ATTRIBUTE_NORMAL, 0);
   IF sendPipe = INVALID_HANDLE_VALUE THEN BEGIN
     fSlaveInitErrorNum:= GetLastError; (* 230: bad pipe. 231: pipe 
busy.        *)

That invariably fails with an error 231, at which point after quite a 
lot of tinkering and comparison against my older code I gave up.

-- 
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]



More information about the fpc-pascal mailing list