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

dzhpxtsq  于 2023-05-22  发布在  其他
关注(0)|答案(8)|浏览(171)

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

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

现在,handler看起来像这样:

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

如果我想做一些特别的事情,比如。删除临时文件,我可以提供这些文件作为这个处理程序的参数吗?
编辑0:谢谢你的回答。我们通常避免/不鼓励使用全局变量。在这种情况下,如果你有一个庞大的程序,事情可能会在不同的地方出错,你可能需要做很多清理工作。为什么API要这样设计?

5w9g7ksd

5w9g7ksd1#

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

  • 回复编辑0:* 历史原因。信号是一个非常古老和非常低级的设计。基本上,你只是给内核一个单一的地址,一些机器代码,并要求它去这个特定的地址,如果这样或那样发生。我们又回到了“可移植汇编器”的思维方式,内核提供了一个简单的基线服务,无论用户进程可以合理地期望自己做什么,它都必须自己做。

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

jc3wubiy

jc3wubiy2#

一个信号处理器注册 * 已经是一个全局状态 *,等同于全局变量。所以使用全局变量传递参数并没有更大的冒犯。然而,这是一个巨大的错误(除非你是Maven,否则几乎可以肯定 * 未定义的行为 *!)从信号处理程序执行任何操作。如果您只是阻塞信号并从主程序循环中轮询它们,则可以避免所有这些问题。

e5njpo68

e5njpo683#

这是一个很老的问题,但我想我可以告诉你一个很好的技巧,可以回答你的问题。不需要使用sigqueue或任何东西。
我也不喜欢使用全局变量,所以我必须找到一种聪明的方法,在我的情况下,发送一个void ptr(你可以稍后转换为任何适合你需要的)。
其实你可以这样做:

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

那么你的sighhandler看起来像这样:

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);
  • 在您的sighhandler函数中 *:
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);
}
yyyllmsg

yyyllmsg4#

当然可以。你可以通过使用sigqueue()而不是通常的kill()将整数和指针传递给信号处理程序。
http://man7.org/linux/man-pages/man2/sigqueue.2.html

vh0rcniy

vh0rcniy5#

将文件名存储在全局变量中,然后从处理程序访问它。信号处理程序回调将只传递一个参数:导致问题的实际信号的ID(例如SIGINT、SIGTSTP)
编辑0:“必须有一个坚实的理由不允许参数的处理程序。”<--有一个中断向量(基本上,一组跳转地址到例程的每个可能的信号)。给定触发中断的方式,基于中断向量,调用特定函数。不幸的是,不清楚与变量关联的内存将在哪里被调用,并且根据中断,内存实际上可能被损坏。有一种方法可以解决这个问题,但是这样就不能利用现有的int 0x 80汇编指令(有些系统仍然在使用)

oxosxuxt

oxosxuxt6#

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

ndh0cuux

ndh0cuux7#

你可以使用一个信号处理器,它是一个类的方法。然后该处理程序可以访问该类中的成员数据。我不完全确定Python在C信号()调用的背后做了什么,但它一定是重新确定数据的作用域?
我很惊讶这是有效的,但它确实有效。运行此命令,然后从另一个终端终止该进程。

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)
xu3bshqb

xu3bshqb8#

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

volatile sig_atomic_t sig_received = 0;

void sigterm_handler(int signum)
{
    printf("SIGTERM. PID: %d\n", getpid());
    sig_received = 1;
}
    void sigint_handler(int signum)
{
    fprintf(stderr, "SIGINT. PID: %d\n", 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向编译器发出信号,该变量不能被优化,因为它可能会发生意外的变化,例如信号的修改。
在一系列线程的例子中,使用这个标志可以不使用全局变量,以一种安全的方式处理闭包

相关问题