【问题标题】:System signal interception in JuliaJulia中的系统信号拦截
【发布时间】:2020-07-03 11:28:37
【问题描述】:

在 Linux 下运行的 Julia 程序中,我需要在调整控制台窗口大小时启动专用操作。那么在 Julia 中,我如何拦截系统信号 SIGWINCH(调整窗口大小)并为其附加一个执行所需操作的函数?

在 Ada 中,声明它相当简单:

 protected Signalhandler is
      procedure Handlewindowresizing;
      pragma Attach_Handler (Handlewindowresizing, SIGWINCH);
 end Signalhandler;

基于 SCHEMER 想法的暂定解决方案:我尝试使用一个 C 库来进行 SIGWINCH 中断监控。

myLibrary.h

void Winresize (void Sig_Handler());

myLibrary.c

#include "myLibrary.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void Winresize(void sig_handler (void)) { 
     signal(SIGWINCH, sig_handler);
}

编译和库准备

gcc -c -Wall -fPIC myLibrary.c

gcc -shared -fPIC -o myLibrary.so myLibrary.o

使用 C 库的 Julia 程序:

function getc1()    
ret = ccall(:jl_tty_set_mode, Int32, (Ptr{Cvoid},Int32), stdin.handle, true)    
ret == 0 || error("unable to switch to raw mode")    
c = read(stdin, UInt8)    
ccall(:jl_tty_set_mode, Int32, (Ptr{Cvoid},Int32), stdin.handle, false)    
c    
end

function traitement() println(displaysize(stdout)); end    
Mon_traitement_c = @cfunction(traitement, Cvoid, ())    
ccall((:Winresize, "/home/Emile/programmation/Julia/myLibrary.so"), Cvoid, (Ptr{Cvoid},), Mon_traitement_c)

while true    
println(getc1())    
end 

Julia 程序运行正常,但是当调整终端窗口大小时,会发出分段错误(核心转储),并且说程序退出时代码为:139。

所以问题是这个分段错误来自哪里?从编译模型? Julia 无权控制 C 管理信号监控的内存部分的代码执行?

删除 Sig_handler 中的 println 操作可抑制分段错误:

curr_size = displaysize(stdout)
new_size = curr_size
function traitement()  global new_size ; new_size = displaysize(stdout); return end

Mon_traitement_c = @cfunction(traitement, Cvoid, ())

ccall((:Winresize, "/home/Emile/programmation/Julia/myLibrary.so"), Cvoid, (Ptr{Cvoid},), Mon_traitement_c)

while true 
    global curr_size, new_size
    if new_size != curr_size
       curr_size = new_size
       println(curr_size)
    end
    sleep(0.1)  
end  

【问题讨论】:

  • 使用 ccall((:signal...) 和 @cfunction 将其实现为 SignalHandlers.jl 模块应该相当简单,但 AFAIK 这还没有完成。
  • 您的建议很好。谢谢。

标签: julia signals ada


【解决方案1】:

是的,这确实是一个后备解决方案,这几乎不是人们对充满承诺的新语言所期望的......但由于没有画眉,我们实际上可以吃黑鸟(微笑)。

但是,如果 Julia 没有计划能够考虑 Unix/Linux 世界的系统信号,则可以使用像 signal.h 访问的 C 库这样的 C 库来做到这一点。

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

 void sig_handler(int signum)
 {
    printf("Received signal %d\n", signum);
 }

int main()
{
   signal(SIGINT, sig_handler);
   sleep(10); // This is your chance to press CTRL-C
   return 0;
}

当接收到系统信号时,我们必须定义一个 julia 函数来执行预期的操作。使其在 C 中用作 Sig_handler 并从 julia 调用 C 语句 signal(SIGWINCH, Sig_handler);

我对 julia 不够熟悉,无法编写确切的代码。但这就是想法......

【讨论】:

  • 我会努力实现你的建议。
  • @Emile 如果您设法实现它(包括编写 Jullia 的 ccal)并希望稍后将其制成标准 Julia 包,我可以帮助打包它。
  • 注意!我必须在 julia 文档中进一步了解。
  • @Przemyslaw Szufel:您对上面显示的分段错误的分析是什么,作为我的问题的补充,并且在使用 C 函数捕获中断时发生?
  • 我还没有编写 Julia-C 集成代码。但是,我知道很长一段时间以来,每当在 Julia 线程中使用任何系统 IO 时都会出现段错误,因此可能存在一些问题。也许在第一步中尝试看看当你只 println("boo") 而不询问终端大小时发生了什么。
【解决方案2】:

由于到目前为止没有人回答这个问题,一种可能的解决方法是在某些时间间隔内异步监控终端的大小。

function monitor_term(func)
    @async begin 
        curr_size = displaysize(stdout)
        while (true)
            sleep(0.1)
            new_size = displaysize(stdout)
            if new_size != curr_size
                curr_size = new_size
                func()
            end
        end
    end
end

现在示例用法:

julia> monitor_term(() -> print("BOO!"))
Task (runnable) @0x0000000013071710

只要终端处于活动状态,对其大小的任何更改都会打印BOO!

【讨论】:

  • 我不知道这种获取当前控制台窗口大小的好方法。 displaysize(stdout) 谢谢
猜你喜欢
  • 1970-01-01
  • 2015-10-04
  • 1970-01-01
  • 2022-07-07
  • 1970-01-01
  • 2012-02-27
  • 2010-12-28
  • 1970-01-01
  • 2021-07-06
相关资源
最近更新 更多