向信号处理程序提供/传递参数

时间:2011-08-07 01:56:27

标签: c signals signal-handling

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

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

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

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

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

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

7 个答案:

答案 0 :(得分:50)

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

回复编辑0:历史原因。信号是一个非常古老而且非常低级的设计。基本上你只是给内核一个地址一些机器代码,并要求它去这个特定的地址,如果发生这种情况。我们回到了这里的“便携式汇编程序”思维模式,其中内核提供了简洁的基线服务,无论用户进程可以合理地预期为什么,它都必须自己做。

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

答案 1 :(得分:16)

信号处理程序注册已经是一个等同于全局变量的全局状态。因此,使用全局变量将参数传递给它并不是更大的冒犯。然而,这是一个巨大的错误(几乎可以肯定未定义的行为,除非你是专家!)无论如何都要从信号处理程序做任何事情。如果您只是阻止信号并从主程序循环中轮询它们,则可以避免所有这些问题。

答案 2 :(得分:6)

这是一个非常古老的问题,但我想我可以向你展示一个可以解决问题的好方法。 不需要使用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呢?

在这里&#39>如何: 初始化

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

在你的sighandler func中  :

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);
}

答案 3 :(得分:4)

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

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

我认为您最好在sa_flags中使用SA_SIGINFO,这样处理程序将 void signal_handler(int sig, siginfo_t *info, void *secret) 在siginfo_t中,您可以提供参数。 Ty:快乐代码

答案 6 :(得分: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)