Linux环境编程 day04 中断、信号、计时器

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 <signal.h>
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函数的效果基本一致,但使用计时器更精细,但准确。
上一篇:C 高级编程day04 多维数组与结构体强化


下一篇:day04