[英]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.