【问题标题】:Is setitimer() call inherited by children孩子是否继承了 setitimer() 调用
【发布时间】:2019-04-18 12:50:15
【问题描述】:

我正在编写代码分叉(3、5、... 不定数)。我希望我的程序在指定的时间后结束(父母首先杀死它的孩子,然后可能通过调用 _exit 来杀死自己,这也是 sig-safe)。我的意思是在信号处理程序中,我通过 kill() 杀死所有孩子,然后为所有孩子调用 waitpid(),因为两者都是异步信号安全函数。为此,我在分叉之前使用setitimer(ITIMER_REAL, &timer, NULL

那么它是由分叉的孩子继承的吗?

如果它不是继承的,你能提供一个来源吗?

如果是继承的,是否所有的孩子都会在这段时间结束后结束?另外,其实我不想要这个案子。

【问题讨论】:

  • @JonathanLeffler 先生,在时间完全过去后,主进程(父进程)通过调用 SIGKILL 杀死它的子进程,因为它们只要它们还活着就服务(接受请求)。在通过一个循环向它们所有人发送 SIGKILL 后,父级再次运行另一个循环以等待它们实际清理进程表资源等。
  • 我怀疑您的意思是“使用 SIGKILL 调用 kill()”而不是“调用 SIGKILL”,因为 SIGKILL 不是可以调用的函数。谨慎使用 SIGKILL;它阻止进程执行任何清理代码。考虑将 SIGHUP 或 SIGTERM 发送给子进程,然后等待它们清理,只向任何没有足够快死的顽固的子进程发送 SIGKILL 可能是明智的。
  • @JonathanLeffler 首先,我的意思是用 SIGKILL 调用 kill()。你的意思是通过调用 SIGHUP 或 SIGTERM 而不是 SIGKILL 我应该处理你提到的信号之一,这样如果我分配了一些带有 malloc 的地方,我就可以进行清理。那么,您能否扩展您的意思,对任何死得不够快的顽固儿童也说 SIGKILL?
  • @JonathanLeffler 还说清理是指关闭文件描述符吗?还是应该做更多的事情?如果是,我应该怎么做?

标签: c linux timer fork setitimer


【解决方案1】:

没有继承。

POSIX spec for fork 明确提到计时器没有继承并且 XSI (timer_create/timer_settime) 计时器被重置:

  • [XSI] [选项开始] 间隔计时器应在子进程中重置。 [选项结束]
  • 父进程创建的每进程计时器不应被父进程继承 子进程。

一个测试程序,例如:

#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <signal.h>
#include <string.h>
#include <sys/time.h>

void h(int Sig)
{
    char pid[20];
    sprintf(pid,"%d\n",(int)getpid());
    (void)write(1,pid,strlen(pid));
}
int main()
{
    if(0>sigaction(SIGALRM,&(struct sigaction){.sa_handler=h},0)) return perror("sigaction"),1;
    if(0>setitimer(ITIMER_REAL, &(struct itimerval){.it_value.tv_sec=1},0)) return perror("setitimer"),1;
    pid_t ch; if(0>(ch=fork())) return perror("fork"),1;
    pause();
    if(ch){
        sleep(1);
        kill(ch,SIGTERM);
    }
    _exit(0);
}

显示处理程序只在父进程中运行——它只打印一个 pid。

【讨论】:

  • 首先感谢您的回答。 IIRC,printf 变体函数不是 asnyc-sig-safe。您知道在信号处理程序中安全打印 PID 的任何替代方法吗?
  • @concurrencyboy 是的,但sprintf通常是安全的,所以我善意地使用它而不是printf。您始终可以推出自己的 AS-safe number-to-string 函数和write() 结果。
  • 我认为最好使用 sig_atomic_t 类型标志,然后在必要时对其进行轮询。
  • 另外,我需要在以下问题中打开新问题吗?使用管道,如果未设置 O_NONBLOCK,则读写块。我怎样才能让 setitimer 继续计数?它不会继续阻塞。不需要任何额外的线程/进程就可以完成吗?
  • @concurrencyboy 计时器绝对会继续运行,即使您的线程/进程被阻塞。除非您的阻塞 (sigprocmask) 或忽略信号,否则其处理程序将运行,通常会中断阻塞调用(导致 EINTR 错误或部分读/写计数)。
猜你喜欢
  • 2019-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-02
  • 2013-04-06
  • 2017-12-09
  • 1970-01-01
相关资源
最近更新 更多