2013-12-18 83 views
2

我有一个来自(老式)教科书的程序,旨在说明在UNIX上使用POSIX信号。该程序运行一个计算循环来计算从固定点开始的完美数字。C + UNIX,siglongjmp和sigsetjmp

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

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);} 

我的问题是:

  1. 它为什么称之为无效状态();和void query();首先在主要?
  2. 在if语句检查开始== 0并决定退出之后,它会出现一行叫做“sigprocmask(SIG_UNBLOCK,& mask,NULL);”为什么我必须在退出后解除封锁?
+2

你在写什么K&R式(非原型)函数定义?除了使用原型符号以外,切勿写新代码! (至少,你需要解释为什么这可能是必要的;没有支持POSIX的平台有一个不支持原型的C编译器,所以你必须非常有说服力地说话。) –

+0

@JonathanLeffler我没写过功能。这是书中的代码,我试图理解它。 – jackhao

回答

4
  1. 这些两行声明的功能status()query()为返回空隙。他们没有指定他们采取什么参数。在现代C语言中,在另一个函数中声明函数是一种诅咒(并且声明它们没有完整的原型也是令人厌恶的 - 但这似乎是另一天的讨论,因为它不是你的代码)。函数应该在其他函数之外声明,如果它们在另一个文件中定义或使用,则应该在头文件中声明它们。如果它们在当前文件中定义并且未在其他文件中使用,则应声明它们并将其定义为static函数。

  2. 变量begin被非正统初始化。在代码的第一遍中设置为2;在从sigsetjmp()非零返回后,它由用户输入设置。它也可能被setjmp()东西毁坏,因为它没有标记为volatile。规则是深奥的。

    但是,其意图是,如果begin为零,则程序退出。否则,它会继续。 sigprocmask()旨在解除任何被屏蔽的信号。我不清楚这是否有必要。当你从信号处理器返回时,即使你通过siglongjmp()退出,被阻塞的信号也应该被解除阻塞 - 我想 -

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


仔细阅读功能的手册页:

Chris Dodd正确时他commentssigsetjmp()与第二个参数为0不保存当前信号掩码。请注意,mask的值是在调用setjmp()后修改的局部变量,并且未标记为volatile,因此当setjmp()返回非零值时其值为不确定的(请参阅setjmp()手册页中的注意事项)。

手册页为sigsetjmp()的理由部分是有趣的阅读,并提到出现在4.2 BSD类似的功能(1982年发行),所以我对他们的评论在70年代不存在仍然有效(K & [R第1版和第7 Edition UNIX™分别于1978年和1979年发布)。名字是AFAICT,由POSIX发明(BSD系统包括_setjmp()_longjmp(),而不是)。

+1

如果我们及时运回到70年代,你们的答案是否属实? –

+1

到了70年代 - 问题还没有定论,因为在K&R第1版和第7版UNIX™(我学习C和Unix的地方;这个系统大多是7号混合系统的时候,并不存在像sigsetjmp()带有一些System III增强功能的版本,IIRC)。这些功能出现在80年代末或90年代初,是POSIX标准化的结果 - POSIX的第一个版本于1988年发布。 –

+0

而且'sigaction()'及相关函数在70年代也不存在; 'sigprocmask()'也没有。他们也是POSIX发明(合理化)。 –