21

有没有办法在 GNU Prolog 中“捕获”(例如“捕获”)操作系统信号?(我使用的是 Ubuntu/Linux,最新的 gprolog)。

我想很久以前我在 WAMCC 中使用过这种方法,在它演变成 GNU Prolog 之前:

:- catch(Long_Running_Goal,signal(2),write('program interrupted'))

但是,如果我使用(重复,失败)无限循环来测试这个,例如

:- catch((repeat,fail),X,write(X)).

在解释器中,Ctrl-C 仍然将我带到跟踪/调试器,如果我用 等中断编译程序,它就会kill -1退出kill -2

我已经尝试编译程序--no-top-level以防默认顶层以某种方式捕获信号,但这没有任何区别。

SWI-Prolog 似乎有一个合适的内置谓词on_signal可以达到目的,但如果可能的话,我正在寻找带有 gprolog 的解决方案。

4

2 回答 2

11

感谢mescalinum确认信号处理在 GNU Prolog 中默认不可用

但是 GNU Prolog 对 C 中的用户例程有很好的支持,我已经能够编写少量 C 代码来捕获 Linux 信号并触发(如果需要)Prolog 异常(注意我的是 Ubuntu 14.04/GNU Prolog 1.3 .0 所以init_signal函数的C 类型Bool来自 gprolog.h - 这在 gprolog.h 1.3.1 之后发生了变化PlBool- 请参阅1.3.0最近的手册):

C代码“signal.c”:

#include <stdio.h>
#include <signal.h>
#include <gprolog.h>

/* signal handler */
void sig_handler(int signo)
{
  if (signo == SIGHUP)
  {
    printf("received SIGHUP\n");
    /* throw Prolog exception */
    Pl_Err_Instantiation();
  }
}

/* GNU Prolog  goal that registers the signal handler */
/* declared with :- foreign(init_signal).             */
Bool init_signal()
{
  if (signal(SIGHUP, sig_handler) == SIG_ERR)
  {
        printf("\ncan't catch SIGHUP\n");
  }
  printf("%s","SIGHUP handler registered\n");
  return TRUE;                  /* succeed */
}

Prolog“test.pl”中的测试用法——本例中的“长时间运行”查询是 o_query,用于“catch”关系,可以用 SIGHUP 中断:

:- foreign(init_signal).

:- initialization(main).

main :- write('Prolog signal test program started'),
        nl,
        init_signal,
        catch(o_query,X,write('Prolog exception thrown')),
        nl,
        halt.

o_query :- repeat,
           sleep(1),
           fail.

编译gplc test.pl signal.c

现在,如果程序使用 ./test 运行,它可以从另一个终端中断kill -1 <test process id>

Bambam@desktop:~/prolog/signal$ ./test
Prolog signal test program started
SIGHUP handler registered
received SIGHUP
Prolog exception thrown
Bambam@desktop:~/prolog/signal$

出于我的目的,当我在 C 信号处理程序中时,我可以有效地处理传入的异常,但将其反射回 Prolog 的“抛出”(在本例中为“实例化错误”)使代码在 Prolog 中保持整洁。

我希望能够向正在执行的 GNU Prolog 进程发送(和捕获)信号的原因是因为我的系统是一个高性能并行处理 Prolog 环境,它可以触发任何长时间运行的 Prolog 进程将自己动态“拆分”成然后在其他机器上执行的多个部分。但是你基本上不能(用我的方法)预测工作的确切分布,并且在适当的时候其他处理器将被中断(即发送一个信号)以进一步分割工作量。

于 2015-06-29T08:30:08.897 回答
10

查看当前使用的gprolog 源代码signal()后:

  • src/BipsPl/os_interf_c.c: signal(SIGPIPE, SIG_IGN);
  • src/EnginePl/LINUX_SIGSEGV.c: signal(SIGSEGV, (void (*)()) SIGSEGV_Handler);
  • src/EnginePl/PPC_SIGSEGV.c: signal(SIGSEGV, (void (*)()) SIGSEGV_Handler);
  • src/EnginePl/SOLARIS_SIGSEGV.c: signal(SIGSEGV, (void (*)()) SIGSEGV_Handler);
  • src/EnginePl/stacks_sigsegv.c: signal(SIGSEGV, (void (*)(int)) SIGSEGV_Handler);
  • src/EnginePl/WIN32_all_SIGSEGV.c: signal(SIGSEGV, (void (*)(int)) SIGSEGV_Handler);
  • src/Linedit/ctrl_c.c: signal(sig, Wrapper_Handler);
  • src/Linedit/ctrl_c.c: signal(SIGINT, Wrapper_Handler);

我们可以看到信号的唯一用途是:

  • 在 REPL中处理SIGINT(通过按CTRL+生成)C
  • 处理SIGSEGV
  • 忽视SIGPIPE

所以这是不可能的,除非你愿意修改源代码。

此外,我在 git 提交消息中找不到任何关于信号的提及。

于 2015-06-24T00:58:20.603 回答