当前位置: 首页 > 面试题库 >

在可可macOS应用程序中陷阱SIGINT

徐晔
2023-03-14
问题内容

我正在尝试为针对MacOS制作的UI应用程序捕获SIGINT。在应用程序委托类中,我看到以下方法:

func applicationWillTerminate(_ aNotification: Notification) {

}

但是,Ctrl+ C,SIGINT,永远不会陷入这里。在互联网上阅读表明,不能保证执行此功能,尤其是在应用程序在后台运行时。

我可以在应用程序委托中做什么以捕获SIGINT?还是我还有其他地方可以捕获中断,以便可以适当地关闭资源?


问题答案:

Charles的回答是正确的,但是他的警告(“确保仅从处理程序中调用可重入函数”)是一个极端的限制。使用kqueue和可以将信号处理重定向到更安全的环境CFFileDescriptor

TN2050技术说明:在没有轮询的情况下观察过程寿命是另一个主题,但它说明了该技术。苹果在那里以这种方式描述了查尔斯的警告:

监听信号可能很棘手,因为与信号处理程序关联的执行环境很古怪。具体来说,如果您安装了信号处理程序(使用signal或sigaction),则必须非常小心在该处理程序中执行的操作。从信号处理程序调用的函数很少。例如,使用malloc!分配内存是不安全的。

sigaction手册页上列出了可从信号处理程序中 安全使用的 功能(
异步信号安全 功能)。

在大多数情况下,您必须采取额外的步骤将传入的信号重定向到更合理的环境。

我从那里获取了代码说明,并对其进行了修改以进行处理SIGINT。抱歉,是Objective-C。这是一次性设置代码:

// Ignore SIGINT so it doesn't terminate the process.

signal(SIGINT, SIG_IGN);

// Create the kqueue and set it up to watch for SIGINT. Use the 
// EV_RECEIPT flag to ensure that we get what we expect.

int kq = kqueue();

struct kevent changes;
EV_SET(&changes, SIGINT, EVFILT_SIGNAL, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, NULL);
(void) kevent(kq, &changes, 1, &changes, 1, NULL);

// Wrap the kqueue in a CFFileDescriptor. Then create a run-loop source
// from the CFFileDescriptor and add that to the runloop.

CFFileDescriptorContext context = { 0, self, NULL, NULL, NULL };
CFFileDescriptorRef kqRef = CFFileDescriptorCreate(NULL, kq, true, sigint_handler, &context);
CFRunLoopSourceRef rls = CFFileDescriptorCreateRunLoopSource(NULL, kqRef, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);

CFFileDescriptorEnableCallBacks(kqRef, kCFFileDescriptorReadCallBack);
CFRelease(kqRef);

这是实现sigint_handler上面引用的回调的方法:

static void sigint_handler(CFFileDescriptorRef f,  CFOptionFlags callBackTypes, void *info)
{
    struct kevent event;

    (void) kevent(CFFileDescriptorGetNativeDescriptor(f), NULL, 0, &event, 1, NULL);
    CFFileDescriptorEnableCallBacks(f, kCFFileDescriptorReadCallBack);

    // You've been notified!
}

请注意,此技术要求您在有兴趣处理SIGINT(也许是应用程序的生命周期)并维护/运行其运行循环的线程上运行安装代码。系统出于自身目的创建的线程(例如,服务于Grand
Central Dispatch队列的线程) 适合此目的。

该应用程序的主线程将正常工作,您可以使用它。 但是
,如果主线程锁定或变得无响应,则它不为运行循环提供服务,并且SIGINT不会调用处理程序。由于SIGINT经常用于恰好中断这种卡住的过程,因此主线程可能不适合。

因此,您可能想产生一个自己的线程只是为了监视此信号。它不应该做任何其他事情,因为其他任何事情也可能导致它卡住。即使在那里,也存在问题。您的处理程序函数将在您的该后台线程上被调用,并且主线程可能仍被锁定。在系统库中,有很多东西仅是主线程的,您将无能为力。但是,与POSIX样式的信号处理程序相比,您将拥有更大的灵活性。

我应该补充一点,GCD的调度源也可以监视UNIX信号,并且更易于使用,尤其是从Swift中。但是,它们不会预先创建运行该处理程序的专用线程。该处理程序将被提交到队列。现在,您可以指定一个高优先级/高QOS队列,但是我不确定如果该进程有多个运行中的失控线程正在运行,则该处理程序将运行。也就是说,实际上在高优先级队列上运行的任务将优先于低优先级线程或队列,但是启动新任务可能不会。我不确定。



 类似资料:
  • while (<STDIN>) 一定要小心这点。如果你不知怎么回事地得到了假值(如:空行),你的文件可能 停止处理了。假如你在处理文件读取(除非修改了 $/),这种事一般不会发生, 但却可能发生。 你更喜欢这样运行: while (readdir(DIR)) { 假设你有文件名为 0 的话,那么程序将停止,且不会继续处理文件。 更合适的 while 循环看起来像这样: while ( defin

  • 在绝大多数情况下, React都是清晰直观的. 但是也不乏有一些小陷阱, 不注意的话有时候也会给你”意外的惊喜”. 下面我们就来介绍一下这些小陷阱 参考资料 React Gotchas Top 5 React Gotchas

  • 这里归纳了Keras使用过程中的一些常见陷阱和解决方法,如果你的模型怎么调都搞不对,或许你有必要看看是不是掉进了哪个猎人的陷阱,成为了一只嗷嗷待宰(?)的猎物 Keras陷阱不多,我们保持更新,希望能做一个陷阱大全 内有恶犬,小心哟 TF卷积核与TH卷积核 Keras提供了两套后端,Theano和Tensorflow,这是一件幸福的事,就像手中拿着馒头,想蘸红糖蘸红糖,想蘸白糖蘸白糖 如果你从无到

  • 这里归纳了Keras使用过程中的一些常见陷阱和解决方法,如果你的模型怎么调都搞不对,或许你有必要看看是不是掉进了哪个猎人的陷阱,成为了一只嗷嗷待宰(?)的猎物 Keras陷阱不多,我们保持更新,希望能做一个陷阱大全 内有恶犬,小心哟 TF卷积核与TH卷积核 Keras提供了两套后端,Theano和Tensorflow,这是一件幸福的事,就像手中拿着馒头,想蘸红糖蘸红糖,想蘸白糖蘸白糖 如果你从无到

  • 问题内容: 我希望能够检测到何时写入内存地址-例如通过设置附加到中断的回调。有人知道吗? 我希望能够在运行时执行此操作(可能gdb具有此功能,但是我的特定应用程序导致gdb崩溃)。 问题答案: 如果要拦截对某个地址范围的写入,则可以使用将有问题的内存标记为不可写,并安装信号处理程序以捕获生成的SIGSEGV,进行日志记录或其他操作,然后将页面再次标记为可写。

  • 通常,Python 旨在成为一门简洁一致的语言,避免发生意外。然而,有些情况可能会给新手们造成困惑。 在这些情况中,有一些虽是有意为之,但还是有潜在风险。还有一些则可以说是语言设计缺陷了。总之,下面列出的这些情况都是些乍一看很不好理解的行为,不过一旦您了解了这些奇怪行为背后的机理,也就基本上能理解了。 可变默认参数 似乎每个 Python 新手都会感到惊讶的一点是 Python 在函数定义中对待可