我有一本(古老的)教科书中的程序,旨在说明UNIX上POSIX信号的使用。该程序运行一个计算循环,以从固定点开始计算理想数。

  • 时间警报信号用于定期打印状态。
  • 中断信号用于按需状态。
  • 退出信号用于重置测试间隔(或终止)。

  • void perfect(int);
    
    sigjmp_buf jmpenv; /* environment saved by setjmp*/
    
    int n; /* global variable indicating current test point */
    
    int main() {
    
        int begin; /* starting point for next search*/
            /* interrupt routines*/
        void status();
        void query();
    
        sigset_t mask;
        struct sigaction action;
    
    
        if (sigsetjmp(jmpenv,0)) {
            printf("Enter search starting point (0 to terminate): ");
            scanf("%d",&begin);
            if (begin==0) exit(0);
            sigprocmask(SIG_UNBLOCK, &mask, NULL);
            }
        else begin=2;
    
        /* Status Routine will handle timer and INTR */
    
        sigemptyset(&mask);
        sigaddset(&mask, SIGINT);
        sigaddset(&mask, SIGALRM);
        sigaddset(&mask, SIGQUIT);
        action.sa_flags=0;
        action.sa_mask=mask;
    
        action.sa_handler=status;
        sigaction(SIGINT,&action,NULL);
        sigaction(SIGALRM,&action,NULL);
    
        action.sa_handler=query;
        sigaction(SIGQUIT,&action,NULL);
    
        /* start alarm clock */
        alarm(20);
        perfect(begin);
    }
    
    void perfect(start)
        int start;
    {
        int i,sum;
    
        n=start;
    
    while (1) {
        sum=1;
        for (i=2;i<n;i++)
            if (!(n%i)) sum+=i;
    
        if (sum==n) printf("%d is perfect\n",n);
        n++;
        }
    }
    
    void status(signum)
    int signum;
    {
    
        alarm(0); /* shutoff alarm */
    
        if (signum == SIGINT) printf("Interrupt ");
        if (signum == SIGALRM) printf("Timer ");
    
        printf("processing %d\n",n);
    
        alarm(20);  /*restart alarm*/
    }
    
    void query() {siglongjmp(jmpenv,1);}
    

    我的问题是:
  • 为什么调用void status();和void query();首先是主要的?
  • 如果if语句检查begin == 0并决定退出,它将遵循名为“sigprocmask(SIG_UNBLOCK,&mask,NULL);”的行。为什么我退出后必须将其解锁?
  • 最佳答案

  • 这两行代码将函数status()query()声明为返回void。他们没有指定要接受的参数。在现代C语言中,在另一个函数中声明函数就是“厌恶”(anathema)(而在没有完整原型(prototype)的情况下声明它们也是“厌恶”,但这似乎是另一天的讨论,因为它不是您的代码)。函数应在其他函数之外声明,并且如果它们在其他文件中定义或使用,则应在 header 中声明。如果它们是在当前文件中定义的,而未在任何其他文件中使用,则应将它们声明并定义为static函数。
  • 变量begin被非常规地初始化。在第一次通过代码时将其设置为2;在sigsetjmp()返回非零值之后,它由用户输入设置。由于未标记为setjmp(),它也很可能被volatile所破坏。规则是深奥的。
    但是,其目的是如果begin为零,则程序退出。否则,它将继续。 sigprocmask()旨在取消屏蔽任何被屏蔽的信号。我不清楚这是否必要。从信号处理程序返回时,即使您通过siglongjmp()退出,阻塞的信号也应解除阻塞(我认为是)。

  • 请注意,在信号处理程序中调用printf()会调用未定义的行为。可能会好的,但是不能保证。在POSIX standard或其他有关SO的问题中都有一个可以调用的函数列表(我知道我之前已经给出了该列表)。

    请仔细阅读手册页中的功能:
  • sigsetjmp()
  • siglongjmp()
  • setjmp()
  • longjmp()

  • Chris Dodd带有第二个参数为0的sigsetjmp()不保存当前信号掩码时,comments是正确的。请注意,mask的值位于调用setjmp()之后被修改的局部变量中,并且未标记为volatile,因此当setjmp()返回非零值时其值是不确定的(请参见setjmp()手册页中的警告)。sigsetjmp()手册页的基本原理部分非常有趣,并提到了4.2 BSD(于1982年发布)中出现的类似功能,因此,我对它们在70年代不存在的评论仍然有效(K&R 1st Edition和7th Edition UNIX™在2003年发布)。分别为1978年和1979年)。 sig*名称是POSIX发明的AFAICT(BSD系统包括_setjmp()_longjmp())。

    09-06 01:10