簡體   English   中英

為什么在收到 SIGINT 后沒有阻塞 read() 中斷?

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

有這個代碼:

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

我希望在 2 秒后中斷read() 但是讀取會不確定地阻塞。 怎么樣? SIGINT不應該中斷 read() 嗎?

signal()並不清楚系統調用是中斷還是自動重啟; 它可能因平台而異。 請參閱手冊頁,在末尾的“注釋/可移植性”部分; 據說在 Linux 上, signal()使用 BSD 語義,這相當於在sigaction()中對某些系統調用使用SA_RESTART (請參閱此頁面中的“信號處理程序中斷系統調用和庫函數”部分)。

sigaction()提供了更好的控制。

您可以替換signal(SIGALRM, sigalarm_handler); 經過

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

在調用read()之后立即放置printf() ) 表明在使用sigaction()時該調用被中斷,但在使用signal()時不會中斷(至少在我的系統上)。

正如問題的評論中所述,循環沒有停止的事實本質上是由於算法的笨拙: if未初始化或不相關的變量進行各種嘗試(問題中的代碼已更改多次,現在使用nbytes好的),測試錯誤errno ...

這是一個嘗試在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