简体   繁体   English

为什么在收到 SIGINT 后没有阻塞 read() 中断?

[英]Why is not blocking read() interrupted after receiving SIGINT?

having this code:有这个代码:

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

#define BSIZE 16

static void sigalarm_handler(int signo)
{
    //cause SIGINT by returning
    return;
}

int main()
{
    sigset_t sigset;
    ssize_t nbytes;
    char buf[BSIZE];
     struct sigaction action;

    //initialize sigset and signal handler
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGALRM);
     memset(&action, 0, sizeof(action));
     action.sa_handler = sigalarm_handler;
     sigaction(SIGALRM, &action, NULL);

    //infinite loop
    while (1)
    {
        alarm(2);
        printf("enter some input (3 chars)\n");

        sigprocmask(SIG_UNBLOCK, &sigset, NULL);
        //should SIGALRM should interupt read after 2 secs
        nbytes = read(fileno(stdin), buf, 3);
        sigprocmask(SIG_BLOCK, &sigset, NULL);

        if (nbytes < 0)
        {
            if (errno == EINTR)
            {
                break;
            }
        }

        buf[3] = '\0';

        //sleep should get SIGALRM, which in turn calls sigalarm_handler which generates SIGINT and interupts sleep, but the SIGALRM shouldn't be wasted, because it is prolong until it is unblock and thus next loop should break out
        sleep(2);
        printf("you wrote: %s\n", buf);
    }
}

I would expect to interupt read() after 2 secs.我希望在 2 秒后中断read() But the read blocks indeterminately.但是读取会不确定地阻塞。 How's that?怎么样? shouldn't SIGINT interrupt the read()? SIGINT不应该中断 read() 吗?

signal() is not perfectly clear about whether a system call is interrupted or automatically restarted; signal()并不清楚系统调用是中断还是自动重启; it may vary from one platform to another.它可能因平台而异。 See the man page , in the "NOTES/Portability" section at the end;请参阅手册页,在末尾的“注释/可移植性”部分; it is stated that on Linux signal() uses the BSD semantics, which is equivalent to using SA_RESTART in sigaction() for certain system-calls (see this page in the "Interruption of system calls and library functions by signal handlers" section).据说在 Linux 上, signal()使用 BSD 语义,这相当于在sigaction()中对某些系统调用使用SA_RESTART (请参阅此页面中的“信号处理程序中断系统调用和库函数”部分)。

sigaction() offers a better control. sigaction()提供了更好的控制。

You may replace signal(SIGALRM, sigalarm_handler);您可以替换signal(SIGALRM, sigalarm_handler); by经过

struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler=sigalarm_handler;
sigaction(SIGALRM, &action, NULL);

Putting a printf() right after the call to read() shows that this call is interrupted when using sigaction() but not when using signal() (at least on my system).在调用read()之后立即放置printf() ) 表明在使用sigaction()时该调用被中断,但在使用signal()时不会中断(至少在我的系统上)。

As stated in the comments of the question, the fact that the loop does not stop is essentially due to clumsiness in the algorithm: various attempts of if with uninitialised or irrelevant variables (the code in the question was changed several times, now with nbytes it's OK), testing the wrong errno ...正如问题的评论中所述,循环没有停止的事实本质上是由于算法的笨拙: if未初始化或不相关的变量进行各种尝试(问题中的代码已更改多次,现在使用nbytes好的),测试错误errno ...

Here is an example trying to make explicit the situation after read() .这是一个尝试在read()之后明确情况的示例。

sigprocmask(SIG_UNBLOCK, &sigset, NULL);
nbytes = read(fileno(stdin), buf, 3);
int read_errno=errno; // save errno because the next call to
                      // sigprogmask() could overwrite it
sigprocmask(SIG_BLOCK, &sigset, NULL);
if(nbytes==0)
{
  printf("EOF reached (Control-d for example)\n");
  break;
}
if(nbytes<0) // read() failed
{
  if(read_errno==EINTR)
  {
    printf("interrupted by a signal while reading\n");
  }
  else
  {
    printf("something really bad happened: %s\n",
           strerror(read_errno));
  }
  break;
}
printf("%d bytes were read\n", (int)nbytes); // read() succeeded
buf[nbytes] = '\0';
printf("you wrote: <%s>\n", buf);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM