C 信号处理器赢得';看不到全局变量

C 信号处理器赢得';看不到全局变量,c,signals,scope,signal-handling,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> #inc

问题是:这个程序应该接收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 = countbyte;    
}

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);
}
/*cpinout.c*/
#包括
#包括
#包括
#包括
#包括
#定义BUF_大小1024
易失性信号原子计数字节=0;
易挥发sig_原子sig_t sigcount=0;
/*我的处理器:gestore di信号*/
静态无效信号发生器(内部信号){
如果(sigcount!=0)
fprintf(stderr,“在%d字节后中断。\n”,sigcount);
sigcount=countbyte;
}
内部主(空){
INTC;
字符缓冲区[BUF_大小];
结构动作;
sigemptyset(和action.sa_mask);
action.sa_标志=0;
action.sa_handler=sighandler;
if(sigaction(SIGUSR1,&action,NULL)=-1){
fprintf(stderr,“sigusr:sigaction\n”);
出口(1);
}
while(c=getc(stdin)!=EOF){
countbyte++;
fputc(c,stdout);
}
返回(0);
}

根据C89和标准,信号只能写入
易失性sig\u原子\u t
变量:

如果信号处理程序引用除errno[Option End]之外的任何对象[CX][Option Start],且该对象具有静态存储持续时间,而不是通过向声明为volatile sig_原子的对象赋值,则该行为是未定义的

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


编辑

在您提到的注释中,您正在以以下方式运行命令:

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;
}
#包括
#包括
#包括
#包括
int countbyte=0;//主程序
int sigcount=0;//用于信号处理器
/*我的处理器:信号处理器*/
静态无效信号发生器(内部信号)
{
sigcount=countbyte;
}
内部主(空)
{ 
INTC;
struct-sigaction-sigact;
sigemptyset(&sigact.sa_mask);
sigact.sa_标志=0;
sigact.sa_handler=signandler;
sigaction(SIGUSR1和sigact,NULL);
而((c=getc(stdin))!=EOF){
countbyte++;
fputc(c,stdout);
}
如果(sigcount!=0){
printf(“在%d字节之后中断,\n”,sigcount);
}
返回0;
}

您能否给出一个提示,为什么您认为signal和sigaction之间的差异在这里是相关的?@AProgrammer-文档中指出,signal()的行为在UNIX版本中有所不同,在Linux的不同版本中也有不同。避免使用:使用sigaction(2)代替。。。signal()的唯一可移植用途是将信号的配置设置为SIG_DFL或SIG_IGN。使用signal()建立信号处理程序时的语义因系统而异(POSIX.1明确允许这种变化);不要将其用于此目的。是的,unix变体之间的行为存在差异,我不知道与报告的问题有关。@AndreaMazzocchi-您的操作系统是什么?Linux Xubuntu 12.10 3.5.0-23-generic即使使用sigaction>,也无法工作。<我仍然复制了数百万字节