【问题标题】:Handling signals in different ways以不同的方式处理信号
【发布时间】:2014-10-31 04:50:20
【问题描述】:

谁能帮我理解以下三种处理信号的方式有什么区别?我在 C 中的客户端/服务器中运行。

编辑:我知道第一个例子是错误的,现在我想知道哪个更好/可能,第二个还是第三个?我还在网上读到有人在它们之间进行混合,使用“sigemptyset”和“sigaddset”中的“struct sigaction sig”,没有任何 sigprocmask。这比我的两种解决方案都好吗?

处理程序:

void closeSig(){
    close(socketAccept);
    close(socket);
    exit(1);
}

第一个例子:

signal(SIGINT, closeSig);

第二个例子:

sigset_t set;
struct sigaction sig;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sig.sa_sigaction = &closeSig;
sig.sa_flags = SA_SIGINFO;
sig.sa_mask = set;
sigaction(SIGINT, &sig, NULL);
sigprocmask(SIG_UNBLOCK, &set, NULL);

第三个例子:

struct sigaction sig;
sig.sa_sigaction = &closeSig;
sig.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &sig, NULL);

【问题讨论】:

  • 提问前你搜索了吗?你看过What is the difference between sigaction() and signal()?你缺少什么信息吗?你为什么不提到你看过它?
  • @JonathanLeffler 是的,很抱歉这是一个错字。我已经搜索了但我没有找到你的帖子,这对sigaction()和signal()之间的区别非常清楚。但是还有一个案例:使用 sigaction 与 sigset+sig_unblock 或不使用 sigset 的区别? ://
  • 您在问题中显示sigprocmask(),但在评论中提及sigset() 及其亲属(sigrelse()sighold()sigpause()sigignore())。还有pthread_sigmask()。通常不应使用sigset() 系列——它们被标记为“过时”,新代码不应使用它们。你真正感兴趣的是什么?
  • 我觉得从信号处理程序调用exit() 不是个好主意。
  • @JonathanLeffler 我在大学学习,为了学习目的,我被要求创建一个服务器/客户端并处理信号,这就是为什么我想了解两者之间的区别第二个例子和第三个例子。就我得到的结果而言,如果我使用第二个示例或第三个示例,它会是一样的吗?

标签: c sockets signals signal-handling


【解决方案1】:

根据 POSIX sigaction(),函数 closeSig() 严格来说不是一个适合信号的回调。应该是:

void closeSig(int signum);

对于常规回调,但是当您使用 SA_SIGINFO 时,它必须是:

void closeSig(int signum, siginfo_t *info, void *context);

您还需要查看sigprocmask() 的 POSIX 规范。

我们来看第二个例子:

sigset_t set;
struct sigaction sig;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sig.sa_sigaction = &closeSig;
sig.sa_flags = SA_SIGINFO;
sig.sa_mask = set;
sigaction(SIGINT, &sig, NULL);
sigprocmask(SIG_UNBLOCK, &set, NULL);

&closeSig 上的 & 是不必要的,但无害。但是,问题中显示的closeSig() 的类型是错误的。 sigset_t 表示SIGINT(仅)在调用中断处理程序时会被阻塞,但无论如何都会发生这种情况,因为标志不包括SA_NODEFER。因此,处理set 的代码对于sigaction() 来说是多余的。

sigprocmask() 的调用会解除对中断的阻塞 (SIGINT)。目前尚不清楚为什么要这样做;必须有一些先前对sigprocmask() 的调用阻止中断才能发挥作用。但是,在此之后,如果向进程发送中断,则将调用 closeSig() 函数并使用它不期望的参数。

第三个例子是:

struct sigaction sig;
sig.sa_sigaction = &closeSig;
sig.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &sig, NULL);

这与剖析和简化第二个示例中描述的最小操作非常接近。主要问题是sig.sa_mask 被设置为一个不确定的值。代码应该是:

struct sigaction sig;
sig.sa_sigaction = &closeSig;
sig.sa_flags = SA_SIGINFO;
sigemptyset(&sig.sa_mask);
sigaction(SIGINT, &sig, NULL);

这相当于第二个例子。

【讨论】:

  • 感谢您的耐心等待,现在事情有点清楚了。现在,假设我还必须处理其他信号,例如 SIGALARM。处理完 sigalarm 后,它会重新启用“sigaction(SIGALARM, &signAlarm, NULL);”然后将控件返回给函数“fun()”。如果我们看第二个例子,设置了 sigset_t 并且我们将 sigprocmask unblock 放在 fun() 的开头,这是有道理的,因为这可以再次处理所有信号,对吧?在这种情况下,sigset_t 可以被认为是有用的,因为我可以将所有我想要的信号添加到其中并通过 sigprocmask 调用将它们全部解锁,对吗?
  • 当我写“it re-enebles”时,我的意思是在处理程序中我放了那个代码,然后是“fun();”。再次感谢!
猜你喜欢
  • 2015-10-27
  • 1970-01-01
  • 2010-12-10
  • 2018-10-02
  • 2020-07-28
  • 1970-01-01
  • 1970-01-01
  • 2020-08-26
  • 1970-01-01
相关资源
最近更新 更多