测试代码如下
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
static void sigfunc(int signo)
{
if(signo == SIGUSR1)
{
printf("receive sigusr1\n");
}
}
int main()
{
char str[10];
if(signal(SIGUSR1, sigfunc) == SIG_ERR)
return -1;
while(1)
{
memset(str, 0, sizeof(str));
read(fileno(stdin), str, 10);
printf("read from stdin\n");
printf("%s",str);
}
return 0;
}
程序从标准输入中使用read读取数据,read是一个低速系统调用,按照posix.1标准,默认的方式是重启由信号中断的系统调用,
编译该代码,执行,会阻塞在read上,此时使用kill(1)发送一个SIGUSR1信号给该程序,若自动重启由信号中断的系统,则不会立马输出read from stdin。
kill -USR1 pid
测试结果表明linux系统确实重启了read系统调用。
另附上apue上的一段话:
对于中断的read,write系统调用,(read)允许该系统调用成功返回,返回已经收到的部分数据量,(write)允许该系统调用成功返回,返回也写的部分数据量。
我的理解是:
测试代码中的read是一个字节都没有读,所以重启了,但是上面一段话的意思是已经读/写了,但未读/写完时,依照posix标准,返回成功,即不重设errno
//上面的是linux下的默认处理方法,使用sigaction可以改变
代码如下:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
typedef void (*Sigfunc)(int);
Sigfunc signal_intr(int signo, Sigfunc func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_flags |= SA_INTERRUPT;
if(sigaction(signo, &act, &oact) < 0)
return (SIG_ERR);
return oact.sa_handler;
}
void sigfunc(int)
{
printf("receive SIGUSR1\n");
}
int main()
{
char str[10];
if(signal_intr(SIGUSR1, sigfunc) == SIG_ERR)
return -1;
while(1)
{
memset(str, 0, sizeof(str));
read(fileno(stdin), str, 10);
printf("receive.\n");
printf("%s", str);
}
}
改变是使用了SA_INTERRUPT标记,它将使sigaction函数不再重启被中断的系统调用。
即阻塞在read时收到SIGUSR1信号后输出如下:
receive SIGUSR1
receive.
之后再经while迭代到read阻塞中。如果read那里改成如下形式
if(read(fileno(stdin), str, 10) < 0)
{
if(errno == EINTR)
{
printf("interrupted by signal.\n");
}
}
那么再被信号中断后,下面提示也会输出
interrupted by signal.