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系统 ...
随机推荐
- 第八章 高级搜索树 (xa1)红黑树:动机
- 【校招面试 之 剑指offer】第10-3题 矩阵覆盖问题
题目:我们可以使用2✖️1的小矩形横着或者竖着去覆盖更大的矩形.请问用8个2✖️1的小矩形无重叠地覆盖一个2✖️8的大矩形,共有多少种方法? 分析:当放第一块时(假定从左边开始)可以横着放,也可以竖着 ...
- java web 常用正则
什么是 RegExp? RegExp 是正则表达式(Regular expression)的缩写,作用是对字符串执行模式匹配. 通常用于格式验证.正则替换.查找子串等 各种编程语言的正则表达式基本相同 ...
- iOS - OC - 字典快速遍历
1. [dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop ...
- 算法笔记_067:蓝桥杯练习 算法训练 安慰奶牛(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路.道路被用来连接N个牧场,牧场被连续地编号为1到N.每一个牧场都是 ...
- php多进程 防止出现僵尸进程
对于用PHP进行多进程并发编程,不可避免要遇到僵尸进程的问题. 僵尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程(zombie)进程.任何进程在退出前(使用exit退出) ...
- 提交代码到远程GIT仓库,代码自动同步到远程服务器上。
现在一般都会通过github,gitlab,gitee来管理我们的代码.我们希望只要我本地push了代码,远程服务器能自动拉取git仓库的代码,进行同步. 这就需要用到各仓库为我们提供的webhook ...
- 手机端图片预览和缩放js
转至:http://blog.sina.com.cn/s/blog_c342e3090102vcxu.html 1.手机端的图片选择和预览 <input type="file" ...
- phython学习
Python 中文学习大本营 关于作者 赞助本站 The Python Tutorial (Python 2.7.X) 的中文翻译版本.Python Tutorial 为初学 Python 必备官方教 ...
- PAT 1020 月饼 (25)(精简版代码+思路+推荐测试用例)
1020 月饼 (25)(25 分)提问 月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼.现给定所有种类月饼的库存量.总售价.以及市场的最大需求量,请你计算可以获得的最大收益是 ...