linux系统编程之信号(七):被信号中断的系统调用和库函数处理方式
一些IO系统调用执行时, 如 read 等待输入期间, 如果收到一个信号,系统将中断read, 转而执行信号处理函数. 当信号处理返回后, 系统遇到了一个问题: 是重新开始这个系统调用, 还是让系统调用失败?早期UNIX系统的做法是, 中断系统调用, 并让系统调用失败, 比如read返回 -1, 同时设置 errno 为 EINTR中断了的系统调用是没有完成的调用, 它的失败是临时性的, 如果再次调用则可能成功, 这并不是真正的失败, 所以要对这种情况进行处理, 典型的方式为:
while (1) { n = read(fd, buf, BUFSIZ); if (n == -1 && errno != EINTR) { printf("read error\n"); break; } if (n == 0) { printf("read done\n"); break; } }
这样做逻辑比较繁琐, 事实上, 我们可以从信号的角度来解决这个问题, 安装信号的时候, 设置 SA_RESTART属性, 那么当信号处理函数返回后, 被该信号中断的系统调用将自动恢复.
示例程序:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>
#include <unistd.h> void sig_handler(int signum)
{
printf("in handler\n");
sleep(1);
printf("handler return\n");
} int main(int argc, char **argv)
{
char buf[100];
int ret;
struct sigaction action, old_action; action.sa_handler = sig_handler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
/* 版本1:不设置SA_RESTART属性
* 版本2:设置SA_RESTART属性 */
//action.sa_flags |= SA_RESTART; sigaction(SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN) {
sigaction(SIGINT, &action, NULL);
} bzero(buf, 100); ret = read(0, buf, 100);
if (ret == -1) {
perror("read");
} printf("read %d bytes:\n", ret);
printf("%s\n", buf); return 0;
}
当sa_flags不设置:SA_RESTART时:
结果:
设置后:
当被中断后,重新执行
man帮助说明:
Interruption of system calls and library functions by signal handlers
If a signal handler is invoked while a system call or library
function call is blocked, then either: * the call is automatically restarted after the signal handler
returns; or * the call fails with the error EINTR. Which of these two behaviors occurs depends on the interface and
whether or not the signal handler was established using the
SA_RESTART flag (see sigaction(2)). The details vary across UNIX
systems; below, the details for Linux. If a blocked call to one of the following interfaces is interrupted
by a signal handler, then the call will be automatically restarted
after the signal handler returns if the SA_RESTART flag was used;
otherwise the call will fail with the error EINTR: * read(2), readv(2), write(2), writev(2), and ioctl(2) calls on
"slow" devices. A "slow" device is one where the I/O call may
block for an indefinite time, for example, a terminal, pipe, or
socket. (A disk is not a slow device according to this
definition.) If an I/O call on a slow device has already
transferred some data by the time it is interrupted by a signal
handler, then the call will return a success status (normally,
the number of bytes transferred). * open(2), if it can block (e.g., when opening a FIFO; see
fifo(7)).
* wait(2), wait3(2), wait4(2), waitid(2), and waitpid(2). * Socket interfaces: accept(2), connect(2), recv(2), recvfrom(2),
recvmsg(2), send(2), sendto(2), and sendmsg(2), unless a
timeout has been set on the socket (see below). * File locking interfaces: flock(2) and fcntl(2) F_SETLKW. * POSIX message queue interfaces: mq_receive(3),
mq_timedreceive(3), mq_send(3), and mq_timedsend(3). * futex(2) FUTEX_WAIT (since Linux 2.6.22; beforehand, always
failed with EINTR). * POSIX semaphore interfaces: sem_wait(3) and sem_timedwait(3)
(since Linux 2.6.22; beforehand, always failed with EINTR). The following interfaces are never restarted after being interrupted
by a signal handler, regardless of the use of SA_RESTART; they always
fail with the error EINTR when interrupted by a signal handler: * Socket interfaces, when a timeout has been set on the socket
using setsockopt(2): accept(2), recv(2), recvfrom(2), and
recvmsg(2), if a receive timeout (SO_RCVTIMEO) has been set;
connect(2), send(2), sendto(2), and sendmsg(2), if a send
timeout (SO_SNDTIMEO) has been set.
* Interfaces used to wait for signals: pause(2), sigsuspend(2),
sigtimedwait(2), and sigwaitinfo(2). * File descriptor multiplexing interfaces: epoll_wait(2),
epoll_pwait(2), poll(2), ppoll(2), select(2), and pselect(2). * System V IPC interfaces: msgrcv(2), msgsnd(2), semop(2), and
semtimedop(2). * Sleep interfaces: clock_nanosleep(2), nanosleep(2), and
usleep(3). * read(2) from an inotify(7) file descriptor. * io_getevents(2). The sleep(3) function is also never restarted if interrupted by a
handler, but gives a success return: the number of seconds remaining
to sleep.
linux系统编程之信号(七):被信号中断的系统调用和库函数处理方式的更多相关文章
- Linux系统编程(22)——响应信号
进程对信号的响应 进程可以通过三种方式来响应一个信号: 1.忽略信号,即对信号不做任何处理,其中,有两个信号不能忽略:SIGKILL及SIGSTOP: 2.捕捉信号.定义信号处理函数,当信号发生时,执 ...
- Linux系统编程(2)——文件与IO之系统调用与文件IO操作
系统调用是指操作系统提供给用户程序的一组"特殊"接口,用户程序可以通过这组"特殊"接口来获得得操作系统内核提供的特殊服务.在linux中用户程序不能直接访部内核 ...
- linux系统编程之信号(七)
今天继续学习信号,主要是学习关于时间和定时器相关的函数的使用,关于这个实际上有很多内容,这里先简要进行说明,等之后再慢慢进行相关深入,也主要是为接下来要做的一个综合linux系统编程的例子做准备,好了 ...
- Linux 系统编程 学习:03-进程间通信1:Unix IPC(2)信号
Linux 系统编程 学习:03-进程间通信1:Unix IPC(2)信号 背景 上一讲我们介绍了Unix IPC中的2种管道. 回顾一下上一讲的介绍,IPC的方式通常有: Unix IPC包括:管道 ...
- Linux 系统编程
简介和主要概念 Linux 系统编程最突出的特点是要求系统程序员对它们工作的的系统的硬件和操作系统有深入和全面的了解,当然它们还有库和系统调用上的区别. 系统编程分为:驱动编程.用户空间编程和网络编程 ...
- linux系统编程(一)概述
glibc库封装了linux系统调用,并提供c语言接口 所以学习linux系统编程,主要参考glibc库系统调用相关api 一.进程控制: fork 创建一个新进程 clone 按指定条件创建子进程 ...
- LINUX系统编程 由REDIS的持久化机制联想到的子进程退出的相关问题
19:22:01 2014-08-27 引言: 以前对wait waitpid 以及exit这几个函数只是大致上了解,但是看REDIS的AOF和RDB 2种持久化时 均要处理子进程运行完成退出和父进程 ...
- Linux系统编程-setitimer函数
功能:linux系统编程中,setitimer是一个经常被使用的函数,可用来实现延时和定时的功能. 头文件:sys/time.h 函数原型: int setitimer(int which, cons ...
- Linux系统编程@进程通信(一)
进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统 ...
随机推荐
- Access to the path 'C:\inetpub\wwwroot\mysite\images\savehere' is denied.
访问路径被拒绝 我解决了这个设置: IIS>应用程序池> [您的站点]>高级设置...>标识>内置帐户> LocalSystem
- MyBatis多对多查询
-------------------siwuxie095 MyBatis 多对多查询 以订单和商品为例,即 一个订单可 ...
- IDEA 的VM Option设置加快页面的加载速度
VM Option的设置: -Xms1024M -Xmx2048M -XX:PermSize=128M -XX:MaxPermSize=256M
- 面向对象设计模式纵横谈:Builder 生成器模式(笔记记录)
Builder模式的缘起 假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分要富于变化. 如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正…… 动 ...
- 转载 springboot 配置读取
前言:了解过spring-Boot这个技术的,应该知道Spring-Boot的核心配置文件application.properties,当然也可以通过注解自定义配置文件**.properties的信息 ...
- 谈谈我对Ui设计师的一些观点
做ui设计师3年多了,对ui设计师在工作中也了解了许多. 作为UI设计师,在工作中需要清楚了解设计的目的,尤其是你做的不是大众化产品,不能以个人认知.很强的主题性来确定. 例如针对儿童人群的app时, ...
- DB2数据类型(抄袭)
数字 数据类型 精度 最小值 最大值 smal ...
- <td> 行高多层设置的问题
在一个table中,设置了class,并且对应的样式设置了td的高度时,在其嵌套的table中的td高度不能设置大于父table的td的高度. 只有一种方法可以设置,如下: <table wid ...
- MySQL的left on 【zt】
MySQL的left on [zt] (2008-11-03 17:27:30) 转载▼ 标签: it 分类: 学习笔记 MySQL多表连接查询Left Join,Right Join php开源嘛 ...
- 2018.09.28 bzoj1563: [NOI2009]诗人小G(决策单调性优化dp)
传送门 决策单调性优化dp板子题. 感觉队列的写法比栈好写. 所谓决策单调性优化就是每次状态转移的决策都是在向前单调递增的. 所以我们用一个记录三元组(l,r,id)(l,r,id)(l,r,id)的 ...