【问题标题】:C Language: how do I evaluate the return value of a signal handler?C 语言:如何评估信号处理程序的返回值?
【发布时间】:2020-12-12 14:20:38
【问题描述】:

在我正在编写的代码中,检查信号处理程序的返回值以确保信号是否被接收是非常有用的。所以,例如,如果我有这样的东西:

Message m;
sig_t s = signal(SIGALRM, sigalrm);
alarm(DURATION);
int status = msgrcv(msg_id, &m, sizeof(m.appointment), destination_mailbox, 0);

将会发生的事情是程序一到达 msgrcv 命令就会阻塞,因为它会等待消息。但是,如果它在 DURATION 秒后没有收到消息,则警报信号将唤醒它,状态将等于 -1。

现在,理想情况下,假设我想确保程序由于警报而不是其他原因唤醒。比如说msgrcv出错了,程序就被唤醒了,但是状态还是-1,m为空。

信号状态返回值的man入口

signal() 返回信号处理程序的前一个值,或 SIG_ERR 关于错误。在里面 发生错误时,设置 errno 以指示原因。

如果我在调用信号处理程序后尝试打印 sig_t 的值,我会怎么做?这将打印“信号(零)”。

 printf("signal %p\n", s);

那么,如果我想这样做,我该如何处理这个返回值

if(s == a state where the handler was never called)
      do A;
else
      do B;

【问题讨论】:

  • typedef void (*sig_t) (int); 如您所见,信号处理程序是一个不返回值的函数。
  • 调用signal 不会调用处理程序。如果 signal 返回 NULL,那只是意味着之前没有处理程序。这并不意味着没有收到 SIGALRM。如果您想知道您的处理程序已被调用,请让处理程序更改全局 sig_atomic_t 的值(实际上,这就是您的处理程序应该做的所有事情)。在主进程中,检查该值何时被修改。
  • @WilliamPursell 该死的,我试图不惜一切代价避免全局变量。但是你建议我使用 sig_atomic_t 类型的全局变量?
  • 如果msgrcv及时返回,希望您重置alarm
  • 信号处理程序需要使用文件范围变量——全局或静态。这实际上是不可避免的。对于常规信号处理程序,信号处理程序可用的唯一信息是信号编号。 POSIX 提供sigaction(),它提供选项SA_SIGINFO 并将更多信息传递给处理程序,但仍然无法访问程序员控制的数据——如果您必须访问信号处理程序中的数据,它必须至少是文件范围数据.

标签: c signals interrupt-handling


【解决方案1】:

如果msgrcv 被信号中断,它应该返回-1,并且errno 应该设置为EINTR(除非使用sigaction 更改了行为)。

所以要检查这种情况:

int status = msgrcv(/*...*/);
if (status == -1) {
    if (errno == EINTR)) {
        /* interrupted by signal */
    }
    else {
        /* other error */
    }
}

如果您需要专门检查SIGALRM 中断,您可以让信号处理程序设置一个全局sig_atomic_t 变量,然后在msgrcv 返回后检查它。

【讨论】:

  • 除非使用sigaction 更改了行为 POSIX 没有要求我发现msgrcv() 需要重新启动而不是中断。 The behavior of msgrcv() can not be changed on Linux to be restarted: "msgrcv() 在被信号处理程序中断后永远不会自动重新启动,无论在建立信号处理程序时设置了SA_RESTART 标志。"
猜你喜欢
  • 1970-01-01
  • 2012-01-08
  • 1970-01-01
  • 1970-01-01
  • 2011-11-17
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
  • 2015-11-12
相关资源
最近更新 更多