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



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

/* Signal handling */
struct sigaction act;
act.sa_handler = signal_handler;
/* some more settings */
现在,处理程序看起来像这样:
void signal_handler(int signo) {
    /* some code */
}

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

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

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

对编辑0的响应:历史原因。信号是一种很老很低级的设计。基本上,你只是给内核一个地址,给一些机器码,让它去到这个特定的地址,如果这样或那样发生。在这里,我们又回到了"可移植汇编器"的思维模式,内核提供了一个没有多余的基线服务,无论用户进程可以合理地期望自己做什么,它必须自己做。

同样,通常反对全局变量的参数在这里并不适用。信号处理程序本身是一个全局设置,因此不可能为它设置几个不同的用户指定参数集。(好吧,实际上它不是完全全局的,而只是线程全局的。但是线程API将包含一些线程本地存储机制,这正是您在本例中所需要的)。

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

这是一个很老的问题,但我想我可以告诉你一个很好的技巧,可以回答你的问题。不需要使用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);
}

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

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

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

Edit 0: "必须有一个坚实的理由不允许给处理程序提供参数。"有一个中断向量(基本上,一组跳转地址到每个可能的信号的例程)。给定触发中断的方式,基于中断向量,调用一个特定的函数。不幸的是,不清楚与变量关联的内存将在哪里被调用,并且根据中断,内存实际上可能被破坏。有一种方法可以绕过它,但是你不能利用现有的int 0x80汇编指令(有些系统仍然使用)

我认为你最好在sa_flags中使用SA_SIGINFO,这样处理程序就会得到void signal_handler(int sig, siginfo_t *info, void *secret)在siginfo_t中,你可以提供你的参数。Ty:HAPPY代码

尽管这个问题很古老,但这个问题今天仍然存在。基本上是关闭临时文件,正确终止线程等,例如,可以使用以下逻辑:

volatile sig_atomic_t sig_received = 0;
void sigterm_handler(int signum)
{
    printf("SIGTERM. PID: %dn", getpid());
    sig_received = 1;
}
    void sigint_handler(int signum)
{
    fprintf(stderr, "SIGINT. PID: %dn", getpid());
}
...
int main()
{
    struct sigaction action;
    action.sa_handler = sigterm_handler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGTERM, &action, NULL);
    action.sa_handler = sigint_handler;
    sigaction(SIGINT, &action, NULL);
    pthread_t writer_thread, reader_thread;
    struct master_argv writer_args, reader_args;
    buffer_init(&(writer_args.buffer));
    buffer_init(&(reader_args.buffer));
    writer_args.pipename = PIPE_CAPOSC;
    reader_args.pipename = PIPE_CAPOLET;
    if (pthread_create(&writer_thread, NULL, master, (void *)&writer_args) != 0)
    {
        exit(1);
    }
    if (pthread_create(&reader_thread, NULL, master, (void *)&reader_args) != 0)
    {
        exit(1);
    }
    while (!sig_received)
    {
        sleep(1);
    }
    pthread_join(writer_thread, NULL);
    pthread_join(reader_thread, NULL);
    buffer_destroy(&(writer_args.buffer));
    buffer_destroy(&(reader_args.buffer));
    return 0;
}

基本上,在信号管理器中,设置了一个sig_atomic_t标志,它保证对该变量的原子访问,volatile标志向编译器发出信号,表明该变量不能进行优化,因为它可能会发生意想不到的变化,例如信号的修改。

在一系列线程的例子中,使用此标志可以通过不使用全局变量

以安全的方式处理闭包。

你可以使用一个信号处理程序,它是一个类的方法。然后,该处理程序可以访问该类中的成员数据。我不完全确定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)

相关内容

  • 没有找到相关文章

最新更新