73

我可以向信号处理程序提供/传递任何参数吗?

/* Signal handling */
struct sigaction act;
act.sa_handler = signal_handler;
/* some more settings */

现在,处理程序看起来像这样:

void signal_handler(int signo) {
    /* some code */
}

如果我想做一些特别的事情,即删除临时文件,我可以将这些文件作为参数提供给这个处理程序吗?

编辑0:感谢您的回答。我们通常避免/不鼓励使用全局变量。在这种情况下,如果你有一个庞大的程序,不同的地方可能会出错,你可能需要做很多清理工作。为什么 API 是这样设计的?

4

7 回答 7

66

您不能将自己的数据作为参数传递给信号处理程序。相反,您必须将参数存储在全局变量中。(如果您在安装信号处理程序后需要更改这些数据,请务必非常小心)。

对编辑 0 的回应:历史原因。信号是一种非常古老且非常低级的设计。基本上,您只是为内核提供了某个机器代码的单个地址,并在发生此类情况时要求它转到该特定地址。我们又回到了“便携式汇编器”的思维模式,内核提供了简洁的基线服务,无论用户进程可以合理地期望自己做什么,它都必须自己做。

此外,针对全局变量的常用论点在这里并不适用。信号处理程序本身是一个全局设置,因此不可能有几组不同的用户指定参数集。(嗯,实际上它并不完全是全局的,而只是线程全局的。但是线程 API 将包含一些用于线程本地存储的机制,这正是您在这种情况下所需要的)。

于 2011-08-07T02:00:14.477 回答
18

信号处理程序注册已经是等效于全局变量的全局状态。因此,使用全局变量向它传递参数并没有什么大不了的。但是,无论如何从信号处理程序中执行任何操作都是一个巨大的错误(除非您是专家,否则几乎可以肯定是未定义的行为!)。如果您只是阻塞信号并从主程序循环中轮询它们,则可以避免所有这些问题。

于 2011-08-07T02:49:49.627 回答
9

这是一个非常古老的问题,但我想我可以向您展示一个可以回答您问题的好技巧。无需使用 sigqueue 或其他任何东西。

我也不喜欢使用全局变量,所以我必须找到一个聪明的方法,在我的例子中,发送一个 void ptr (你可以稍后将它转换为任何适合你需要的东西)。

其实你可以这样做:

signal(SIGWHATEVER, (void (*)(int))sighandler); // Yes it works ! Even with -Wall -Wextra -Werror using gcc

然后你的 sighandler 看起来像这样:

int sighandler(const int signal, void *ptr) // Actually void can be replaced with anything you want , MAGIC !

你可能会问:那么如何获得 *ptr 呢?

方法如下: 在初始化时

signal(SIGWHATEVER, (void (*)(int))sighandler)
sighandler(FAKE_SIGNAL, your_ptr);

在您的 sighandler 函数中

int sighandler(const int signal, void *ptr)
{
  static my_struct saved = NULL;

  if (saved == NULL)
     saved = ptr;
  if (signal == SIGNALWHATEVER)
     // DO YOUR STUFF OR FREE YOUR PTR
   return (0);
}
于 2017-04-13T19:20:12.687 回答
8

绝对地。您可以使用 sigqueue() 而不是通常的 kill() 将整数和指针传递给信号处理程序。

http://man7.org/linux/man-pages/man2/sigqueue.2.html

于 2016-01-12T05:58:05.853 回答
1

将文件的名称存储在全局变量中,然后从处理程序访问它。信号处理回调将只传递一个参数:导致问题的实际信号的 ID(例如 SIGINT、SIGTSTP)

编辑 0:“不允许向处理程序提供参数必须有一个坚如磐石的理由。” <-- 有一个中断向量(基本上,每个可能的信号都有一组跳转地址到例程)。给定中断触发的方式,基于中断向量,调用特定函数。不幸的是,不清楚与变量关联的内存将被调用的位置,并且取决于内存可能实际损坏的中断。有一种方法可以绕过它,但是您不能利用现有的 int 0x80 汇编指令(某些系统仍在使用)

于 2011-08-07T02:02:48.533 回答
1

我认为您最好在 sa_flags 中使用 SA_SIGINFO 以便处理程序进入 void signal_handler(int sig, siginfo_t *info, void *secret) siginfo_t 您可以提供您的参数。Ty:HAPPY 代码

于 2020-11-26T09:14:19.927 回答
0

您可以使用作为类方法的信号处理程序。然后该处理程序可以访问该类的成员数据。我不完全确定 Python 在 C signal() 调用周围做了什么,但它必须重新确定数据范围?

我很惊讶这有效,但确实有效。运行它,然后从另一个终端终止该进程。

import os, signal, time

class someclass:
    def __init__(self):
        self.myvalue = "something initialized not globally defined"
        signal.signal(signal.SIGTERM, self.myHandler)
    def myHandler(self, s, f):
        # WTF u can do this?
        print "HEY I CAUGHT IT, AND CHECK THIS OUT", self.myvalue


print "Making an object"
a = someclass()

while 1:
    print "sleeping.  Kill me now."
    time.sleep(60)
于 2012-04-25T15:43:41.237 回答