信号处理程序将无法看到全局变量 [英] Signal handler won't see global variable

查看:149
本文介绍了信号处理程序将无法看到全局变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的问题:这个程序应该从标准输入接收输入,并计算插入的字节;在SIGUSR1信号whill停止主程序和将文件打印标准错误怎么当我发送了SIGUSR1多少字节被复制。

这是我的老师怎么要我这样做:在一个终端类型

 猫的/ dev /零| ./cpinout |猫>的/ dev / null的

,而从第二终端发送信号以

 杀-USR1 XXXX

其中xxxx是cpinout的PID。

我更新了我的previous code:

  / * * cpinout.c /#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;
#包括LT&;&unistd.h中GT;
#包括LT&;&signal.h中GT;#定义BUF_SIZE 1024挥发性sig_atomic_t countbyte = 0;
挥发性sig_atomic_t sigcount = 0;/ * my_handler:gestore迪信号* /
静态无效sighandler(INT正负号){
    如果(sigcount!= 0)
        fprintf中(标准错误,%d个字节后中断\\ n,sigcount);
    sigcount = contabyte;
}诠释主要(无效){    INT℃;
    字符缓冲区[BUF_SIZE]
    结构sigaction的行动;    sigemptyset(安培; action.sa_mask);
    action.sa_flags = 0;
    action.sa_handler = sighandler;
    如果(的sigaction(SIGUSR1,&安培;作用,NULL)== -1){
        fprintf中(标准错误,sigusr:sigaction的\\ n);
        出口(1);
    }
    而(C = GETC(标准输入)!= EOF){
        countbyte ++;
        的fputc(C,标准输出);
    }
    返回(0);
}


解决方案



修改

在你提到你正在运行该命令的意见是:

猫的/ dev /零| ./nam​​efile |猫>的/ dev / null的

行为实际上是罚款。 的/ dev / zero的是零,它正在送往该方案层出不穷。因此,它的计算起来非常快。当你中断,它停止而你留下了一个很大的数字。


的问题可能与这样的事实,而全局变量正在更新的信号处理程序可以被称为(如果需要多于一个的指令)。然而,GNU文档指出它是安全的假设,一个 INT 始终是一个POSIX系统上的原子。

我能想到的唯一的另一种可能性是,我们在调用的fputc 中的循环,用的printf 在处理程序(但应安全的处理程序来调用的printf 如果它不被程序调用)。尝试从环去除的fputc ,看它是否解决了问题。

编辑:

这似乎说明问题。这涉及到一种可安全从信号处理程序中调用函数:


  

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


您的程序中断一个标准输入输出功能,这似乎完全符合这一点。



这里有一个替代方法:

 的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;
#包括LT&;&signal.h中GT;INT countbyte = 0; //主程序
INT sigcount = 0; //为信号处理程序/ * my_handler:信号处理* /
静态无效sighandler(INT正负号)
{
   sigcount = countbyte;
}INT主要(无效)
{
   INT℃;
   结构的sigaction SIGACT;   sigemptyset(安培; sigact.sa_mask);
   sigact.sa_flags = 0;
   sigact.sa_handler = sighandler;
   的sigaction(SIGUSR1,&安培; SIGACT,NULL);
   而((C = GETC(标准输入))!= EOF){
      countbyte ++;
      的fputc(C,标准输出);
   }
   如果(sigcount!= 0){
      的printf(%d字节\\ n后追访,sigcount);
   }   返回0;
}

Here's the problem: this program should receive input from stdin and count the bytes inserted; the SIGUSR1 signal whill stop the main program and will print on file standard error how many bytes have been copied when I send the SIGUSR1.

That's how my teacher wants me to do this: in one terminal type

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

while from a second terminal send signals with

kill -USR1 xxxx

where xxxx is the pid of cpinout.

I updated my previous code:

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

解决方案


EDIT

In the comments you mentioned that you are running the command as:

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

The behaviour is actually fine. /dev/zero is an endless stream of zeros, which are being sent to the program. So it's counting them up very quickly. When you interrupt, it stops and you're left with a large number.


The problem may be related to the fact that the signal handler may be called while the global variable is being updated (if this takes more than one instruction). However, the GNU documentation states that it's safe to assume that an int is always atomic on a POSIX system.

The only other possibility I can think of is that you're calling fputc in the loop, with printf in the handler (it should however be safe to call printf in a handler if it's not being called by the program). Try removing fputc from the loop to see if it resolves the problem.

EDIT:

This appears to explain the problem. This relates to the kind of functions that are safe to call from within a signal handler:

Functions can also be nonreentrant if they use static data structures for their internal bookkeeping. The most obvious examples of such functions are the members of the stdio library (printf(), scanf(), and so on), which update internal data structures for buffered I/O. Thus, when using printf() from within a signal handler, we may sometimes see strange output—or even a program crash or data corruption— if the handler interrupts the main program in the middle of executing a call to printf() or another stdio function. (The Linux Programming Interface)

Your program is interrupting a stdio function, which seems to fit this perfectly.


Here's an alternative approach:

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

这篇关于信号处理程序将无法看到全局变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆