向信号处理程序提供/传递参数
我可以向信号处理程序提供/传递任何参数吗?
/* Signal handling */
struct sigaction act;
act.sa_handler = signal_handler;
/* some more settings */
现在,处理程序如下所示:
void signal_handler(int signo) {
/* some code */
}
如果我想做一些特殊的事情,即删除临时文件,我可以将这些文件作为参数提供给该处理程序吗?
编辑0:感谢您的回答。我们通常避免/不鼓励使用全局变量。在这种情况下,如果您有一个庞大的程序,不同的地方可能会出现问题,您可能需要进行大量的清理工作。为什么API要这样设计?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
您不能将自己的数据作为参数传递给信号处理程序。相反,您必须将参数存储在全局变量中。 (如果您在安装信号处理程序后需要更改这些数据,请务必非常小心)。
回复编辑0:历史原因。信号是一种非常古老且非常低级的设计。基本上,您只是为内核提供了一些机器代码的单个地址,并要求它在发生这种情况时转到这个特定地址。我们又回到了“便携式汇编器”的思维模式,内核提供了一种简单的基线服务,无论用户进程可以合理地期望自己做什么,它都必须自己做。
此外,针对全局变量的常见论点在这里并不适用。信号处理程序本身是一个全局设置,因此不存在为其提供多组不同的用户指定参数的相关可能性。
(嗯,实际上它并不完全是全局的,而只是线程全局的。但是线程 API 将包含一些线程本地存储的机制,这正是本例中您所需要的)。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 change those 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.
Also, the usual arguments against global variables don't really apply here. The signal handler itself is 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).信号处理程序注册已经是一个全局状态,相当于全局变量。因此,使用全局变量向其传递参数并没有什么更大的冒犯。然而,无论如何,从信号处理程序中执行任何操作都是一个巨大的错误(几乎肯定未定义的行为,除非您是专家!)。如果您只是阻止信号并从主程序循环中轮询它们,则可以避免所有这些问题。
A signal handler registration is already a global state equivalent 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 behavior unless 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.
这是一个非常古老的问题,但我想我可以向您展示一个可以回答您的问题的好技巧。
无需使用 sigqueue 或其他任何东西。
我也不喜欢使用全局变量,因此就我而言,我必须找到一种聪明的方法来发送 void ptr(您可以稍后将其转换为适合您需要的任何内容)。
实际上你可以这样做:
那么你的叹息处理程序将如下所示:
你可能会问: 那么如何获取 *ptr 呢?
方法如下:
初始化时
在您的ighandler函数中
:
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.
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).
Actually you can do this :
Then your sighandler would look like this :
You might ask : How to get the *ptr then ?
Here's how :
At initialization
In your sighandler func
:
绝对地。您可以使用 sigqueue() 而不是通常的kill() 将整数和指针传递给信号处理程序。
http://man7.org/linux/man-pages/man2/sigqueue .2.html
Absolutely. You can pass integers and pointers to signal handlers by using sigqueue() instead of the usual kill().
http://man7.org/linux/man-pages/man2/sigqueue.2.html
将文件名存储在全局变量中,然后从处理程序访问它。信号处理程序回调只会传递一个参数:导致问题的实际信号的 ID(例如 SIGINT、SIGTSTP)
编辑 0:“必须有一个坚定的理由不允许向处理程序提供参数。” <-- 有一个中断向量(基本上,是每个可能信号的例程的一组跳转地址)。给定中断触发方式,根据中断向量,调用特定函数。不幸的是,尚不清楚与变量关联的内存将在哪里被调用,并且根据中断,内存实际上可能会被损坏。有一种方法可以解决这个问题,但是您无法利用现有的 int 0x80 汇编指令(某些系统仍在使用)
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)
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)
我认为你最好在 sa_flags 中使用 SA_SIGINFO 这样处理程序就会得到
void signal_handler(int sig, siginfo_t *info, void *secret)
在 siginfo_t 中,您可以提供您的参数。
Ty:HAPPY代码
I think you it's better to use SA_SIGINFO in sa_flags so the handler will get
void signal_handler(int sig, siginfo_t *info, void *secret)
in siginfo_t you can provide your params.
Ty:HAPPY code
尽管这是一个非常古老的问题,但这个问题今天仍然存在。
基本上是为了关闭临时文件、正确终止线程等。例如,可以使用以下逻辑:
基本上,在信号管理器中,设置了一个 sig_atomic_t 标志,它保证对此变量和
的原子访问>volatile
向编译器发出信号,表明该变量不得优化,因为它可能会发生意外的更改,例如信号的修改。使用此标志,您可以通过不使用全局变量以安全的方式处理闭包(在一系列线程的示例中)
Despite the very old question the problem still exists today.
Basically to close temporary files, terminate threads correctly, etc. for example, this logic could be used:
Basically, within the signal manager, a
sig_atomic_t
flag is set which guarantees atomic access to this variable andvolatile
to signal to the compiler that this variable must not be optimized since it could undergo unexpected changes such as the modification by a signal .Using this flag you can handle the closure, in the example of a series of threads, in a safe way by not using global variables
您可以使用信号处理程序,它是类的方法。然后该处理程序可以访问该类的成员数据。我不完全确定 Python 在 C signal() 调用周围做了什么,但它一定是重新界定数据范围?
我很惊讶这有效,但确实如此。运行此命令,然后从另一个终端终止该进程。
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?
I was amazed that this works, but it does. Run this and then kill the process from another terminal.