【问题标题】:Pascal StdIn/StdOut pipes帕斯卡标准输入/标准输出管道
【发布时间】:2015-10-01 04:00:15
【问题描述】:

我正在尝试编写一个由另一个程序作为进程启动的 Pascal (Lazarus/FPC) 程序。调用者(Arena chess GUI)使用 StdIn 和 StdOut 与我的程序对话。

首先,我在我的程序中使用 READLN 来获取从 GUI 发送的文本命令,并使用 WRITELN 来回复它们。效果很好,只是如果 READLN 必须等待来自 GUI 的输入,我的程序将停止执行任何操作。因为我希望程序继续工作并且只在命令到达时处理它们,所以我不得不改变它。

所以我改变了使用的代码:

...
var   inpStream        : TInputPipeStream;
...
inpStream := TInputPipeStream.Create(StdInputHandle);
...
if inpStream.NumBytesAvailable > 0 then begin
    SetLength(s_buffer, inpStream.NumBytesAvailable);
    inpStream.Read(s_buffer[1], length(s_buffer));
end;
...

效果非常好,因为它不再暂停阅读。但随后 WRITELN 停止工作:没有任何内容被发送回 GUI。我想也许这会有所帮助:

...
var inpStream        : TInputPipeStream;
    outStream        : TOutputPipeStream;
...
inpStream := TInputPipeStream.Create(StdInputHandle);
outStream := TOutputPipeStream.Create(StdOutputHandle);
...
if inpStream.NumBytesAvailable > 0 then begin
    SetLength(s_buffer, inpStream.NumBytesAvailable);
    inpStream.Read(s_buffer[1], length(s_buffer));
end;
...
outStream.Write(s_buffer, length(s_buffer));

但这使情况变得更糟,因为它现在不读取或写入任何内容。那么如何在保持写入 StdOut 的能力的同时在 StdIn 上进行非阻塞输入?

【问题讨论】:

    标签: pipe stdout stdin pascal


    【解决方案1】:

    假设您使用 Windows,这可能意味着读取您的输出的程序读取它的频率不够(它让它堆积起来),然后当管道的总大小达到一定大小(通常是几 MB)时windows 停止处理。

    这是一种新情况,需要深入研究 Windows 管道和作业控制。在 FPC 3.x TProcess 中修复了一些错误,它们是相似的(如果没有定期处理 stderr,管道处理会停止,请参阅 intrun 命令代码)。

    如果接收程序不处理stderr,请不要使用。

    【讨论】:

      【解决方案2】:

      嗯,这很尴尬!结果是由于我的程序中的逻辑错误,没有正确发送对 GUI 的回复。感谢您通过 Marco 的回答,是的,我正在使用 Windows。原来如此:

      READLN/WRITELN 工作但停止程序,直到进入 READLN。

      TInputPipeStream/WRITELN 可以在不停止程序的情况下工作,因此可以解决我的问题。

      TInputStream/TOutputStream 似乎不能一起工作,我不知道为什么。是我试图初始化它们的方式还是它们应该是独占的?

      【讨论】: