Linux环境编程 day04 中断、信号、计时器
- 中断
- 信号
-
- 信号的捕获处理
- 发送信号
- 进程休眠
- 闹钟信号
- 信号集与信号屏蔽
- 带参数的信号处理
- 计时器
中断
1、中断的概念
暂停当前执行的任务,转而执行其它任务,待完成后再返回继续执行当前任务。
硬件中断:来自硬件设备的中断
软件中断:来自其它程序的中断
2、信号是一种软件中断,信号提供一种异步执行任务的机制。
3、常见的信号
SIGSEGV(11) 段错误信号 试图访问未映射过虚拟内存,或向没有写权限的内存写入数据 终止+core
SIGINT(2) 终端中断符信号 用户按中断键(Ctrl+C),产生此信号,并送至前台进程组的所有进程 终止
SIGFPE(8) 算术异常信号 表示一个算术运算异常,例如除以0、浮点溢出等 终止+core
信号的默认处理方式:终止、终止+core、忽略
4、不可靠信号
是一种早期的信号机制,小于(34)SIGRTMIN都是不可靠信号。
这些不支持排队,可能会丢失,同一个信号产生多次,但进程只收到一次。
5、可靠信号
位于(34)SIGRTMIN和(64)SIGRTMAX之间的信号都是可靠信号,支持排除不会丢失,安全可靠。
信号
信号的捕获处理
1、先在内核中注册一个信号处理函数。
2、当信号发生时内核会捕获信号并调用信号处理函数。
#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:向内核注册一个信号处理函数
signum:要捕获的信号
handler:
1、信号处理函数的地址
2、SIG_IGN(忽略) SIG_DFL(按默认方式处理)
返回值:成功返回该信号原来的处理方式(函数指针或SIG_IGN(忽略) SIG_DFL)
注意:SIGKILL(9)终止信号,SIGSTOP(19)停止信号,这两个信号既不能被捕获也不能被忽略。
发送信号
1、键盘
Ctrl+c SIGINT(2) 终端中断
Ctrl+\ SIGQUIT(3) 终端退出
Ctrl+z SIGSTP(20) 终端暂停
2、代码错误
除0 SIGFPE(8) 算术异常信号
非法访问内存 SIGSEGV(11) 段错误信S号
硬件故障 SIGBUS(7) 总线错误信号
3、命令
kill -信号 进程号
killall -9 CMD 杀死所有叫CMD的进程
4、函数
int kill(pid_t pid, int sig);
功能:向指定的进程发送信号
int raise(int sig);
功能:进程向自己发送sig信号。
信号处理的一些作用:
1、防止用户误按一些快捷键
2、段错误、浮点例外的收尾
3、提醒
进程休眠
int pause(void);
功能:使调的进程进入休眠状态,直到遇到信号且信号处理函数结束后才返回。
返回值:要么永远不返回,要么被信号中断返回-1。
unsigned int sleep(unsigned int seconds);
功能:使调用的进程休眠seconds秒,当信号发生时会提前结束。
返回值:0(睡够了)或剩余的秒数。
闹钟信号
unsigned int alarm(unsigned int seconds);
功能:在seconds秒后向调用的进程发送闹钟信号,该信号的默认处理方式是终止进程。
seconds:如果为0,则相当于取消闹钟信号。
返回值:上次设置的闹钟信号,还有多少秒产生。
信号集与信号屏蔽
1、信号集:多个信号的集合,类型sigset_t,128位二进制,每一位代表一个信号。
int sigemptyset(sigset_t *set);
功能:设置信号集中所有二进制位为0,清空信号集
int sigfillset(sigset_t *set);
功能:设置信号集中所有二进制位为1,填满信号集
int sigaddset(sigset_t *set, int signum);
功能:向信号集中添加信号
int sigdelset(sigset_t *set, int signum);
功能:从信号集中删除信号
int sigismember(const sigset_t *set, int signum);
功能:判断信号集中是否有某个信号
2、信号屏蔽
信号屏蔽掩码(信号集):里面记录着当前进程不想收到的信号
int sigprocmask(int how, const sigset_t *set,sigset_t *oldset);
功能:设置当前进程的信号屏蔽掩码
how:修改信号掩码的方式
SIG_BLOCK 把参数set中的信号添加到信号屏蔽码中
SIG_UNBLOCK 把参数set中与信号屏蔽码中交集的信号删除
SIG_SETMASK 把参数set中信号拷贝到信号屏蔽码中
set:NULL则忽略,表示只想获取当前进程的信号屏蔽码
oldset:存储当前进程的信号屏蔽码
注意:当信号屏幕码还原时,未决状态的信号会再次发生,继续递送,不可靠信号只递送一次,而可靠信号排队递送。
int sigpending(sigset_t *set);
功能:获取当前进程未决状态的信号。
带参数的信号处理
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
功能:向内核注册信号和处理方式
act:信号处理方式
oldact:旧的信号处理方式
struct sigaction {
void (*sa_handler)(int); // 普通的信号处理函数,与signal的一样
void (*sa_sigaction)(int, siginfo_t *, void *); //带参数的信号处理函数
sigset_t sa_mask; // 信号屏蔽码
int sa_flags;
void (*sa_restorer)(void);//过时了,不用
};
sa_flags:
SA_RESETHAND/SA_ONESHOT 当信号处理完后,恢复默认的信号处理方式。
SA_NOCLDSTOP 如果信号是 SIGCHLD,当子进程暂停时不通知父进程。
SA_NODEFER/SA_NOMASK 在信号处理函数执行过程中不屏蔽当前正在处理的信号。
SA_RESTART 如果系统调用被该信号中断,会自动重启。
SA_SIGINFO 使用sa_sigaction来处理信号
int sigqueue(pid_t pid, int sig, const union sigval
value)
功能:向指定的进程发送sig信号,附加value(整数或指针)。
返回值:成功返回0,失败返回-1;
计时器
1、系统为每个进程维护三个计时器
真实计时器:程序运行的实际时间
虚拟计时器:程序运行在用户态所消耗的时间
实用计时器:程序运行在用户太和内核态所消耗的时间之和
实际用时(真实计时器)=用户时间(虚拟计时器)+内核时间+睡眠时间
int getitimer(int which, struct itimerval *curr_value);
功能:获取计时器的设置
which:计时器类型
ITIMER_REAL 真实计时器 SIGALRM
ITIMER_VIRTUAL 虚拟计时器 SIGVTALRM
ITIMER_PROF 实用计时器 SIGPROF
返回值:成功返回0,失败返回-1。
struct itimerval {
struct timeval it_interval; 每隔多久产生一次时钟信号
struct timeval it_value; 第一次产生时钟信号的时间
};
struct timeval {
long tv_sec; 秒
long tv_usec; 微秒 1=1000000 // 不能超过1000000
};
int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);
功能:设置计时器
which:计时器类型
new_value:新的计时方案
old_value:旧的计时方案,也可以为NULL
注意:与alarm函数的效果基本一致,但使用计时器更精细,但准确。