基本概念:
1、中断
当程序接收到消息后中止了当前正在执行的程序,转而执行其他的任务,等其他任务执行完成后可能再返回继续执行,这种执行模式称为中断执行
分为硬件中断和软件中断
硬件中断由外设硬件产生的中断,例如键盘、鼠标都可以产生,可以屏蔽
软件中断是程序执行了中断指令后产生的中断
2、信号
信号是一种软件中断,是由操作系统发出的中断信号,被程序接收后执行相应的操作
3、常见的信号
kill -l 显示所有信号
SIGINT (2) Ctrl+c 终止
SIGQUIT(3) Ctrl+\ 终止+core(内存映像 内存崩溃)
SIGFPE(8) 除0\溢出 终止+core
SIGKILL(9) 用于杀死进程 终止
SIGSEGV(11) 非法访问内存 终止
4、不可靠信号和可靠信号
建立在早期的信号处理机制上的信号(1-31),称为不可靠信号
不支持排队机制,可能会丢失信号,如果同一个信号连续发送多次,进程可能只接受到了一次
建立在新的信号处理机制上的信号(34~64),称为可靠信号
支持排队机制,如果信号连续发送,也不会丢失
5、信号的来源
硬件异常:除0、非法访问内存、使用了未定义的指令、总线错误
软件异常:通过一些命令、函数产生信号
6、信号的处理
① 忽略
② 终止进程
③ 终止进程+产生core文件
④ 捕获并处理信号(在信号发出前,向内核注册一个信号处理函数,绑定该信号与信号处理函数,当信号发出后,会执行信号处理函数)
信号捕获和注册
typedef void (*sighandler_t)(int);
注意:信号处理函数的格式
参数int表示是导致执行该函数的信号的ID
sighandler_t signal(int signum, sighandler_t handler);
功能:向内核提出绑定一个信号处理函数
signum:信号编号
handler:信号处理函数函数名
还可以写成:
SIG_IGN 忽略处理
SIG_DFL 按默认方式处理
返回值:
返回绑定之前的信号处理函数指针,一般用于记录还原
注意:有个别操作系统通过signal注册的信号只能执行一次信号处理函数,如果想要持续有效,可以在信号处理函数中再重新signal注册一次
注意:虽然有些信号可以捕获,但是产生该信号的错误原因(段错误\除0)依旧还在,如果信号处理函数执行完后不终止进程,就会返回到产生错误的位置,导致死循环,正确的操作是保存数据后,终止进程
信号发出的方式
1、键盘:
Ctrl+c
Ctrl+\
Ctrl+z 暂停\挂起 fg命令恢复最后暂停的进程
2、错误:
非法访问内存
除0
硬件故障、总线错误
(捕获后,要及时终止进程)
3、命令:
kill -信号id 进程号
killall -信号id 进程名
发送信号给所有名字为同名的进程
4、函数:
int kill(pid_t pid, int sig);
功能:向指定的进程发送信号
pid:进程号
sig:信号
int raise(int sig);
功能:给进程自己发送信号
void abort(void);
功能:给进程自己发送SIGABRT(6)信号
unsigned int alarm(unsigned int seconds);
功能:让内核在seconds秒后向进程自己发送SIGALRM(14)信号
返回值:上一次调用后,闹钟剩余的秒数
注意:如果重复调用该函数,只会覆盖之前的设置时间,而不会产生多次闹钟信号
进程休眠与信号
int pause(void);
功能:让调用者进程进入休眠态,直到遇到信号后就会唤醒
返回值:要么一直不返回,要么信号来了返回-1
unsigned int sleep(unsigned int seconds);
功能:让调用者进程进入休眠指定秒数,当遇到信号时会提前返回
返回值:还在休眠中不返回,唤醒后返回剩余睡眠秒数
信号集与信号屏蔽(阻塞):
1、信号集:
是一种数据类型,定义出来的变量可以存储表示多个信号
2、相关函数:
int sigemptyset(sigset_t *set);
功能:清空信号集
int sigfillset(sigset_t *set);
功能:填满信号集
int sigaddset(sigset_t *set, int signum);
功能:向信号集中添加某个信号
int sigdelset(sigset_t *set, int signum);
功能:从信号集中删除某个信号
int sigismember(const sigset_t *set, int signum);
功能:测试查看信号集中是否有某个信号
返回值:
0 不存在
1 存在
-1 信号非法
3 信号屏蔽
当程序执行一些特殊操作时是不适合处理信号的,此时可以让内核先屏蔽信号处理,等特殊操作完成后再继续处理信号
当信号产生时,内核会在该进程中的信号维护表中为该进程标记此信号,一旦完成标记进程就开始响应信号,此过程称为递送
从信号产生到完成递送过程有一个时间间隔,处于这个时间间隔的信号状态叫未决
信号屏蔽就是让信号处于未决状态,暂停递送,当屏蔽解除时再继续进行递送
每个进程都有一个信号集用于存储要屏蔽的信号,称为信号屏蔽集
int sigprocmask(int how, const sigset_t *set, sigset_t *old‐set);
功能:设置信号屏蔽集
how:信号屏蔽的方式
SIG_BLOCK
把set中信号添加到信号屏蔽集中
SIG_UNBLOCK
从信号屏蔽集中删除set中的信号
SIG_SETMASK
把信号屏蔽集中的信号全部替换成set中的信号
set:准备设置的信号集
old-set:获取旧的信号屏蔽集
4 附带信息的高级信号处理
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
功能:向内核注册一个信号处理函数,相当于signal的升级版
signum:要捕获的信号
act:
struct sigaction {
void (*sa_handler)(int);//不附带数据的信号处理函数
void (*sa_sigaction)(int,siginfo_t *,void *);// 附带附加数据的信号处理函数
sigset_t sa_mask; // 信号屏蔽集,在该函数执行时,默认会屏蔽当前信号,如果想要屏蔽其他信号,可以向sa_mask中增加信号
int sa_flags; // 绑定信号的标志位
SA_SIGINFO 使用第二个函数指针进行绑定
SA_NODEFER 在信号绑定中不要屏蔽该信号
SA_RESETHAND 在该信号处理方式执行完后,还原回默认的处理方式
SA_RESTART 系统调用一旦被该绑定的信号打断后,自动重启系统调用
void (*sa_restorer)(void);//保留项 NULL
};
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; //
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count;
POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; //
int si_fd; /* File descriptor */
short si_addr_lsb; /*/
void *si_call_addr; /* Address of system call instruction
(since Linux 3.5) */
int si_syscall; /* Number of attempted system call
(since Linux 3.5) */
}
int sigqueue(pid_t pid,int sig,const union sigval value);
功能:向指定的进程发送附带有数据的信号
pid:进程号
sig:信号ID
value:要附带的数据
union sigval {
int sival_int; //整数
void *sival_ptr; //指针
};
注意:通过这样附带信息的操作,可以让不同的进程进行数据通信
5 定时器
int getitimer(int which,struct itimerval *curr_value);
功能:获取当前定时方案
which:选择计时器
ITIMER_REAL 真实计时器 程序的总运行时间SIGALRM
ITIMER_VIRTUAL 虚拟计时器 用户态的运行时间 SIGVTALRM
ITIMER_PROF 实际计时器 用户态+内核态的运行时间 SIGPROF
真实计时器 = 实际计时器+切换时间+休眠时间
int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);
功能:设置新的定时方案
struct itimerval {
struct timeval it_interval; // 每次计时器产生信号的时间间隔
struct timeval it_value; //第一次信号产生的时间
};
struct timeval {
time_t tv_sec; // 秒
suseconds_t tv_usec; // 微秒
};