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

elm*_*zun 5 c scope signals signal-handling

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

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

cat /dev/zero | ./cpinout | cat >/dev/null
Run Code Online (Sandbox Code Playgroud)

而从第二个终端发送信号

kill -USR1 xxxx
Run Code Online (Sandbox Code Playgroud)

其中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);
}
Run Code Online (Sandbox Code Playgroud)

tep*_*pic 2


\n编辑

\n\n

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

\n\n

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

\n\n

行为其实很好。/dev/zero是无穷无尽的零流,它们被发送到程序。所以它的计数速度非常快。当你打断时,它就会停止,你只剩下一个很大的数字。

\n\n
\n\n

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

\n\n

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

\n\n

编辑:

\n\n

这似乎很能说明问题。这与从信号处理程序中安全调用的函数类型有关:

\n\n
\n

如果函数使用静态数据结构进行内部簿记,那么它们也可以是不可重入的。此类函数最明显的示例是 stdio 库的成员(printf()、scanf() 等),它们更新缓冲 I/O 的内部数据结构。因此,当使用 printf 时() 在信号处理程序中,如果处理程序在中间中断主程序,我们有时可能会看到奇怪的输出\xe2\x80\x94,甚至程序崩溃或数据\n损坏\xe2\x80\x94执行对 printf() 或另一个 stdio 函数的调用。\n(Linux 编程接口

\n
\n\n

你的程序正在中断一个 stdio 函数,这似乎非常适合这一点。\n


\n这是另一种方法:

\n\n

#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <signal.h>\n\nint countbyte = 0;  // for main program\nint sigcount = 0;   // for signal handler\n\n/* my_handler: signal handler */\nstatic void sighandler(int signum)\n{\n   sigcount = countbyte;\n}\n\nint main(void)\n{ \n   int c;\n   struct sigaction sigact;\n\n   sigemptyset(&sigact.sa_mask);\n   sigact.sa_flags = 0;\n   sigact.sa_handler = sighandler;\n   sigaction(SIGUSR1, &sigact, NULL);\n   while ((c = getc(stdin)) != EOF) {\n      countbyte++;\n      fputc(c, stdout);\n   }\n   if (sigcount != 0) {\n      printf("Interrupted after %d bytes\\n", sigcount);\n   }\n\n   return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n