我使用管道来通信两个Prolog进程,每次我到达read/2
谓词从我的管道读取消息时,程序阻塞并保持这样。我不明白为什么会这样(我尝试了一些非常简单的程序),最后我意识到三件事:
- 每次我使用
write/2
发送消息时,发送方进程必须用.n
结束该消息。如果消息没有这样结束,则接收进程将卡在read/2
谓词上。 - 如果发送方没有刷新输出,则消息因此不会留在管道缓冲区中。这似乎是显而易见的,但一开始并不是为了我。
- 当消息没有被刷新时,
read/2
阻塞,而wait_for_input/3
完全不阻塞,所以在这种情况下不需要flush_output/1
。
例子:
这行不通:
example1 :-
pipe(R,W),
write(W,hello),
read(R,S). % The program is blocked here.
这个也不行:
example2 :-
pipe(R,W),
write(W,'hello.n'),
read(R,S). % The program is blocked here.
当这两个,做工作:
example3 :-
pipe(R,W),
write(W,'hello.n'),
flush_output(W),
read(R,S).
example4 :-
pipe(R,W),
write(W,'hello.n'),
wait_for_input([W],L,infinite).
现在我的问题是为什么?Prolog只"接受"是否有原因?当从管道读取时(实际上是从您想要读取的任何流中读取),完整的行以句号结束?为什么read
阻塞而wait_for_input/3
不阻塞(假设消息没有刷新)?
谢谢!
有效的Prolog读取期总是以句点结尾,称为end char (* 6.4.8 *)
。在6.4.8其他标记中,标准读作:
结束字符后跟一个布局字符或
%
。
所以这就是标准的要求。
除了空格、制表符和其他布局字符以及%
之外,句号后的换行符也是结束读项的一种可能。然而,由于tty和相关缓冲的流行,坚持使用换行符似乎是一个很好的约定。
需要结束字符的原因是Prolog语法允许中缀和后缀操作符。考虑作为输入
f(1) + g(2).
在阅读f(1)
时,您可能认为这已经是整个术语了,但是您仍然必须等待句点以确保此后没有中缀或后缀。
还要注意,必须使用writeq/1
或write_canonical/1
来产生可以回读的输出。不能使用write/1
。
作为一个例子,考虑write([(.)+ .]).
首先,这是有效的语法。这些点后面紧跟着其他一些字符。注:.
通常在结尾称为句号,而在Prolog文本中称为点。
write/1
将把它写为[. + .]
。注意,现在第一个.
后面跟着一个空格。所以当这篇文章被重读时,只有[.
会被读取。