UNIX Environmental programming Week2.Day2

信号处理

基本概念

1、中断

​ 当程序接受信息后中止当前执行的程序,转而执行其它任务,等其它任务执行完成后再返回、这种执行模式叫中断、

​ 分为硬件中断和软件中断。

2、信号

​ 是一种软件中断、由操作系统发出、程序接受到后会执行相对应的操作

常见信号产生条件效果
SIGINT(2)Ctrl+C终止
SIGQUIT(3)Ctrl+\终止+core
SIGFPE(8)除0终止+core
SIGKILL(9)终止信号终止
SIGSEGV(11)非法内存访问终止+core
3、什么是可靠信号什么是不可靠信号

​ 建立在早期的信号处理机制上的信号(通过kill -l 获取到的1-31的信号)是不可靠的信号,不支持排队,有丢失的可能

​ 同一个信号如果产生多次,进程可能只接收到一次,

​ 建立在新的信号处理机制上的信号(通过kill -l 获取到的34-64的信号)是可靠的信号,支持排队,不会丢失

4、信号来源

​ 硬件异常:除0、无效的内存访问、未定义的指令、总线错误

​ 软件异常:通过一些命令、函数产生的信号

5、信号的处理方式

​ 1、忽略

​ 2、终止进程

​ 3、终止进程并产生core文件

​ 4、捕获信号并处理信号(当信号发送前、先向内核注册一个函数,当信号来临时让系统自动执行该函数)

信号捕获

	#include <signal.h>
    typedef void (*sighandler_t)(int);
	功能:定义信号处理函数的格式
    
    sighandler_t signal(int signum, sighandler_t handler);
	功能:向内核注册一个信号处理函数
    signum:信号的编号
    handler:函数指针
        SIG_IGN:忽略处理
        SIG_DFL:按照默认方式处理
    返回值:之前的信号处理的方式
        
    注意:有些系统通过signal注册的函数只能执行一次,如果想要持续有效,可以在信号处理函数最后再注册一次递归
    子进程会继承父进程的信号处理方式,如果通过exce系列函数来创建子进程,会恢复子进程处理信号的方式
    如果我们捕获 段错误或者算术异常信号,可能产生死循环,因为信号处理完后会返回信号产生的代码处处理,可能导致死循环。
    正确的段错误和算术异常处理方式:先备份数据,并结束进程

​ 练习1:测试一下1-31中哪个信号不能被捕获处理 9&19

信号发送

​ 键盘:

​ Ctrl+c

​ Ctrl+\

​ Ctrl+z 挂起\暂停

​ 错误:

​ 除0

​ 非法访问内存

​ 硬件故障

​ 命令:

​ kill -信号 进程号 能够对具体的进程发送编号

​ killall 向信号编号 进程名

​ 函数:

    int kill(pid_t pid,int sig);
    功能:向指定的进程发送信号
    int raise(int sig);
    功能:给进程自己发送信号
    void abort(void)
    功能:给进程自己发送SIGABRT
    unsigned int alarm(unsigned int seconds);
	功能:让内核在secondes后向进程发送SIGALRM信号
    返回值:返回上一个alarm的剩余时间
    注意:如果再次调用闹钟函数,会覆盖之前的设置,而不会产生两个闹钟信号

进程休眠信号

	int pause(void)
	功能:让调用者进入休眠状态,知道进程遇到任何信号。
    返回值:要么一直休眠不返回,要么结束休眠返回-1
    相当于没有时间限制的sleep 
	#include <unistd.h>
	unsigned int sleep(unsigned int seconds);
	功能:让调用者进入指定秒数的休眠状态,当遇到信号时也会提前返回
    返回值:返回剩余的休眠时间

信号集与信号阻塞

​ 信号集:是一种数据类型,可以存储多个信号

​ sigset_t 128位的二进制数,每一个二进制位都代表一个信号

​ 相关的函数

    #include <signal.h>
    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 非法信号

​ 信号阻塞

​ 当程序执行一些特殊操作时,不适合处理信号,此时可以让内核先屏蔽信号,等这些操作结束后在发送

​ 当信号产生时,内核会在其维护的信号表中为进程设置一个与信号对应的一个标记,该过程叫做递送。

​ 从信号产生到完成递送,有一个时间间隔,处于这个间隔的信号状态叫做未决。

​ 信号屏蔽 = 信号处于未决状态,暂停递送 当屏蔽解除时继续递送

​ 在每个进程都有一个信号集,专门用于储存要被屏蔽的信号。

	#include <signal.h>
	int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
	功能:设置要屏蔽的信号,这些信号储存在信号集里面
	how:信号屏蔽的方式	
		SIG_BLOCK	把set中的信号添加到要屏蔽的信号集中
		SIG_UNBLOCK	从信号集中删除set的信号	
		SIG_SETMASK	用set替换之前的信号集 1234 567
    set:要设置的set信号集
    oldset:获取旧的屏蔽信号集

带附加信息的信号处理

	#include <signal.h>
	int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
	功能:向内核注册一个信号的处理方式
    signum:要处理的信号是谁
    act:信号处理方式函数
    oldact:获取旧的信号获取方式函数
		struct sigaction {
			void     (*sa_handler)(int); //不带附加数据信号处理函数
			void     (*sa_sigaction)(int, siginfo_t *, void *);//带附加数据的信号处理函数
            sigset_t   sa_mask;//信号屏蔽集 在信号函数执行过程中,会默认屏蔽当前信号,如果想要屏蔽其它信号
            					可以向sa_mask添加信号
            int        sa_flags;//标志处理的标志
            void     (*sa_restorer)(void);//保留、NULL
		};
	       SA_NOCLDSTOP

           SA_NOCLDWAIT (since Linux 2.6)

           SA_NODEFER	在信号处理过程中不要屏蔽当前信号

           SA_ONSTACK

           SA_RESETHAND	该信号处理完成后,会还原为默认的处理方式
                      
           SA_RESTART

           SA_SIGINFO 使用函数2来处理信号
           siginfo_t {
               int      si_signo;    /* Signal number */
               int      si_errno;    /* An errno value */
               int      si_code;     /* Signal code */
               int      si_trapno;   /* Trap number that causedhardware-generated signal
               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;     /* Band event (was int in glibc 2.3.2 and earlier) */
               int      si_fd;       /* File descriptor */
               short    si_addr_lsb; /* Least significant bit of address(since kernel 2.6.32) */
           }

	#include <signal.h>
   	int sigqueue(pid_t pid, int sig, const union sigval value);
	功能:向指定进程发送信号并附加信息
    union sigval
   	{
        int sival_int;
        void *sival_ptr;
    }
            

定时器

	#include <sys/time.h>
	int getitimer(int which, struct itimerval *curr_value);
	功能:获取当前的定时方案
    which:
		ITIMER_REAL	真实计时器 程序运行总时间
        ITMER_VIRTUAL 虚拟计时器 用户态的运行时间
        ITIMER_PROF 实际计时器	用户态+内核态运行时间
        真实计时器 = 实际计时器 + 休眠时间
   		 struct itimerval {
               struct timeval it_interval; 每次始终信号产生的时间间隔
               struct timeval it_value;    第一次产生时钟信号的时间
           };

         struct timeval {
               long tv_sec;                /* seconds */
               long tv_usec;               /* microseconds */
           };

	int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);
	功能:设置新的定时方案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值