Windows:Jupyter 如何引发键盘中断?
Posted
技术标签:
【中文标题】Windows:Jupyter 如何引发键盘中断?【英文标题】:Windows: How does Jupyter throw a keyboard interrupt? 【发布时间】:2019-01-15 19:41:30 【问题描述】:我知道如何中断内核(例如通过点击I
两次或通过在 Web 界面上中断内核)。但是,我为 Python(我使用的是 Windows)构建了一个 C 扩展,它在我的 C++ 代码(一个玩具示例)中处理 CTRL-C 事件:
static int s_interrupted = 0;
BOOL WINAPI consoleHandler(DWORD fdwCtrlType)
switch (fdwCtrlType)
// Handle the CTRL-C signal.
case CTRL_C_EVENT:
s_interrupted = 1;
return TRUE;
int main()
s_interrupted = 0;
int output = 1;
if (!SetConsoleCtrlHandler(consoleHandler, TRUE))
std::cout<<"ERROR: Could not set control handler"<<std::endl;
else
std::cout<<"Control hanlder installed"<<std::endl;
int k = 10000;
while (int i < k)
if (s_interrupted == 1)
output = -1;
break;
output = i
i = i + 1;
return output;
我的主程序的输出根据s_interrupted
的值而变化。换句话说,如果我不按 CTRL+C,程序将完成 while 循环并返回一个整数。如果我按 CTRL+C,while 循环将终止并返回一个不同的整数。我不希望在我的 Python 终端中看到 KeyboardInterrupt
。
当我在终端中调用这个 C 扩展时,它工作正常。但是,当我在 Jupyter 笔记本中执行此操作时,程序的行为就像我从未中断过内核一样。当我中断内核时,Jupyter 不会发送SIGINT
吗?
【问题讨论】:
你读过Jupyter messaging documentation吗?重新启动内核只是前端到后端的另一条消息。 【参考方案1】:您的代码没有安装信号处理程序并且没有使用s_signal_handler
。您需要调用signal
函数来注册您的回调。
#include <atomic>
#include <signal.h>
::std::atomic<bool> s_interrupted;
static void signal_handler(int signal)
s_interrupted = true;
int main()
::signal(SIGINT, &::signal_handler);
【讨论】:
抱歉,我更新了我的代码。s_signal_handler
在这里不需要。我已经有consoleHandler
。 ::signal()
是做什么的?
@user1691278 signal
函数注册信号处理程序,因此您可以实际处理SIGINT
SetConsoleCtrlHandler
不做这项工作吗?
@user1691278 有点像,但它是 Windows 特定的东西,信号处理程序更便携。而且CTRL+C
和SIGINT
不完全一样
那么CTRL+C
是什么?【参考方案2】:
你不能在这里使用consoleHandler()
,因为没有控制台。 IPython 内核是一个“无头”子进程,它根据请求执行代码,由 Jupyter 前端引导。
为了中断正在运行的 IPython 内核,Jupyter 前端使用SIGINT
信号。它在 POSIX 和 Windows 上都这样做;在 Windows 上,Jupyter 使用围绕 CreateEventA
、SetEvent
和 WaitForMultipleObjects
构建的额外基础架构来实现与 POSIX os.killpg(PID, SIGINT)
调用相同的结果;一个单独的线程轮询事件并在主线程中触发SIGINT
信号。
请注意,IPython 内核显式地为它处理的每条消息恢复 Python 默认信号处理程序。见ipykernel.kernelbase.Kernel
implementations for the pre_
and post_handler_hook
methods:
self.saved_sigint_handler = signal(SIGINT, default_int_handler)
和
signal(SIGINT, self.saved_sigint_handler)
这两个钩子在每个消息处理程序之前和之后执行(对于every message sent by the frontend to the kernel process,包括execute messages)。
在 Python 主线程中引发 KeyboardInterrupt
的是 signal.default_int_handler
。如果您的代码必须检测中断,则每次 IPython 执行一个单元格时,它都需要注册自己的 signal
处理程序。
附带说明:独立的交互式 Python 解释器不使用 SetConsoleCtrlHandler
来检测键盘中断或者; Python 源代码中唯一使用的地方是py
launcher,然后才使用返回TRUE
的处理程序使控制代码静音。相反,Python 依赖于Windows sending the SIGINT
signal to all attached console processes for the active console window。
【讨论】:
以上是关于Windows:Jupyter 如何引发键盘中断?的主要内容,如果未能解决你的问题,请参考以下文章