信号处理程序不会看到全局变量

时间:2013-03-19 13:28:09

标签: c signals scope signal-handling

这是问题:这个程序应该从stdin接收输入并计算插入的字节数; SIGUSR1信号将停止主程序并在文件标准错误上打印当我发送SIGUSR1时已经复制了多少字节。

这就是我的老师要我这样做的方式:在一个终端类型

cat /dev/zero | ./cpinout | cat >/dev/null

从第二个终端发送信号

kill -USR1 xxxx

其中xxxx是cpinout的pid。

我更新了以前的代码:

/* cpinout.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

#define BUF_SIZE 1024   

volatile sig_atomic_t countbyte = 0;
volatile sig_atomic_t sigcount = 0;

/* my_handler: gestore di signal */
static void sighandler(int signum) {
    if(sigcount != 0)
        fprintf(stderr, "Interrupted after %d byte.\n", sigcount);
    sigcount = contabyte;
}

int main(void) {

    int c;
    char buffer[BUF_SIZE];
    struct sigaction action;

    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    action.sa_handler = sighandler;
    if(sigaction(SIGUSR1, &action, NULL) == -1) {
        fprintf(stderr, "sigusr: sigaction\n");
        exit(1);
    }
    while( c=getc(stdin) != EOF ) {
        countbyte++;
        fputc(c, stdout);
    }
    return(0);
}

2 个答案:

答案 0 :(得分:3)

信号只能根据C89和POSIX 7标准写出volatile sig_atomic_t个变量:

  

如果信号处理程序引用除了errno [Option End]以外的任何对象[CX] [Option Start]以及静态存储持续时间,而不是通过为声明为volatile的对象赋值sig_atomic_t

,则行为未定义

实现通常提供更多,但我怀疑使用非易失性全局变量或printf是由您提供的。

答案 1 :(得分:2)

<小时/> 的修改

在您提到的评论中,您正在运行命令:

cat /dev/zero | ./namefile | cat >/dev/null

行为实际上很好。 /dev/zero是一个无休止的零流,它被发送到程序中。所以它很快就算了起来。当你打断它时,它会停止并且你留下了很多。


问题可能与以下事实有关:在更新全局变量时可以调用信号处理程序(如果这需要多个指令)。但是,GNU文档声明可以安全地假设int在POSIX系统上始终是原子的。

我能想到的唯一另一种可能性是你在循环中调用fputc,在处理程序中使用printf(但是在调用printf时应该是安全的处理程序,如果它没有被程序调用)。尝试从循环中删除fputc以查看它是否可以解决问题。

修改

这似乎可以解释这个问题。这涉及在信号处理程序中安全调用的函数类型:

  

如果函数使用静态数据结构,则它们也可以是非重入的   他们的内部簿记。最明显的例子就是这样   函数是stdio库的成员(printf(),scanf(),   等等),它更新缓冲I / O的内部数据结构。   因此,当在信号处理程序中使用printf()时,我们可以   有时看到奇怪的输出 - 甚至程序崩溃或数据   腐败 - 如果处理程序在中间中断主程序   执行对printf()或其他stdio函数的调用。   ( Linux编程接口

您的程序正在中断stdio功能,这似乎非常适合这种情况。

<小时/> 这是另一种方法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

int countbyte = 0;  // for main program
int sigcount = 0;   // for signal handler

/* my_handler: signal handler */
static void sighandler(int signum)
{
   sigcount = countbyte;
}

int main(void)
{ 
   int c;
   struct sigaction sigact;

   sigemptyset(&sigact.sa_mask);
   sigact.sa_flags = 0;
   sigact.sa_handler = sighandler;
   sigaction(SIGUSR1, &sigact, NULL);
   while ((c = getc(stdin)) != EOF) {
      countbyte++;
      fputc(c, stdout);
   }
   if (sigcount != 0) {
      printf("Interrupted after %d bytes\n", sigcount);
   }

   return 0;
}