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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6970224/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 09:19:39  来源:igfitidea点击:

Providing/passing argument to signal handler

csignalssignal-handling

提问by hari

Can I provide/pass any arguments to signal handler?

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

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

Now, handler looks like this:

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

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

If I want to do something special i.e. delete temp files, can I provide those files as an argument to this handler?

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

Edit 0: Thanks for the answers. We generally avoid/discourage use of global variables. And in this case, If you have a huge program, things can go wrong at different places and you might need to do a lot of cleanup. Why was the API designed this way?

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

采纳答案by hmakholm left over Monica

You can't have data of your own passed to the signal handler as parameters. Instead you'll have to store your parameters in global variables. (And be really, really careful if you ever need to changethose data after installing the the signal handler).

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

Response to edit 0:Historical reasons. Signals are a really old and really low-level design. Basically you're just given the kernel a single address to some machine code and asking it to go to this specific address if such and such happens. We're back in the "portable assembler" mindset here, where the kernels provide a no-frills baseline service, and whatever the user process can reasonably be expected to to for itself, it must do itself.

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

Also, the usual arguments against global variables don't really apply here. The signal handler itselfis a global setting, so there is no relevant possibility of having several different sets of user-specified parameters for it around. (Well, actually it is not entirely global but only thread-global. But the threading API will include some mechanism for thread-local storage, which is just what you need in this case).

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

回答by R.. GitHub STOP HELPING ICE

A signal handler registration is already a global stateequivalent to global variables. So it's no greater offense to use global variables to pass arguments to it. However, it's a huge mistake (almost certainly undefined behaviorunless you're an expert!) to do anything from a signal handler anyway. If you instead just block signals and poll for them from your main program loop, you can avoid all these issues.

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

回答by David Yeager

Absolutely. You can pass integers and pointers to signal handlers by using sigqueue() instead of the usual kill().

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

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

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

回答by rak007

This is a really old question but I think I can show you a nice trick that would have answered your problem. No need to use sigqueue or whatever.

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

I also dislike the use of globals variables so I had to find a clever way, in my case, to send a void ptr (which you can later cast to whatever suits your need).

我也不喜欢使用 globals 变量,所以我必须找到一种聪明的方法,就我而言,发送一个 void ptr(稍后您可以将其转换为适合您需要的任何内容)。

Actually you can do this :

其实你可以这样做:

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

Then your sighandler would look like this :

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

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

You might ask : How to get the *ptr then ?

你可能会问:那怎么得到*ptr呢?

Here's how : At initialization

方法如下: 在初始化时

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

In your sighandler func:

在您的 sighhandler 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);
}

回答by Foo Bah

Store the names of the files in a global variable and then access it from the handler. The signal handler callback will only be passed one argument: the ID for the actual signal that caused the problem (eg SIGINT, SIGTSTP)

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

Edit 0: "There must be a rock solid reason for not allowing arguments to the handler." <-- There is an interrupt vector (basically, a set of jump addresses to routines for each possible signal). Given the way that the interrupt is triggered, based on the interrupt vector, a particular function is called. Unfortunately, it's not clear where the memory associated with the variable will be called, and depending on the interrupt that memory may actually be corrupted. There is a way to get around it, but then you can't leverage the existing int 0x80 assembly instruction (which some systems still use)

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

回答by drizzo4shizzo

You can use a signal handler which is a method of a class. Then that handler can access member data from that class. I'm not entirely sure what Python does under the covers here around the C signal() call, but it must be re-scoping data?

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

I was amazed that this works, but it does. Run this and then kill the process from another terminal.

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

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)