6

这就是问题所在:这个程序应该从标准输入接收输入并计算插入的字节数;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);
}
4

2 回答 2

4

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

如果信号处理程序引用除 errno [Option End] 以外的任何对象 [CX] [Option Start] 且具有静态存储持续时间,而不是通过将值分配给声明为 volatile sig_atomic_t 的对象,则行为未定义

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

于 2013-03-19T14:21:56.310 回答
2


编辑

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

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

行为其实很好。/dev/zero是无穷无尽的零流,它们被发送到程序。所以它会很快地把它们计算出来。当你打断时,它会停止,你会留下很多。


问题可能与在更新全局变量时可能会调用信号处理程序有关(如果这需要多条指令)。但是,GNU 文档声明可以安全地假设 anint在 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;
}
于 2013-03-19T14:26:44.797 回答