Linux环境编程05

Linux环境编程05

声明:本学习笔记为个人复习所用,有诸多瑕疵,具体可参考Linux环境下man手册相关解释

一、信号相关基本概念

  1. 中断

    当程序接收到消息后中止当前正在执行的程序,转而执行其他人物,等其他任务执行完成后再饭hi,这种执行模式叫做中断,中断又分为硬件中断和软件中断。

  2. 信号

    是一种软件中断,由操作系统发出,程序接收后会执行相应的操作。

  3. 常见的信号
    命令 kill -l可以查看所有的信号

  4. SIGINT(2) ctrl+c 终止

  5. SIGQUIT(3) ctrl+\ 终止+core

  6. SIGFPE(8) 除零 终止+core

  7. SIGKILL(9) 终止信号 不能捕获和忽略

  8. SIGSEGV(11) 段错误信号 终止+core

  9. 不可靠信号和可靠信号
    建立在早期的信号处理机制上(1-31)的信号是不可靠信号,它不支持排队,可能会丢失信号。
    建立在新的信号处理机制上的(34-64)的信号是可靠信号,支持排队,信号不会丢失。

  10. 信号的来源
    硬件异常:除零,非法访问内存,未定义的指令,总线错误,
    软件异常:通过一些命令,函数产生的信号

  11. 信号的处理方式

    1. 忽略
    2. 终止进程
    3. 终止进程并产生core文件(记录内存映像
    4. 捕获并处理

二、信号捕获

typedef void (*sighandler_t)(int);
功能:说明信号处理函数的格式

sighandler_t signal(int signum, sighandler_t handler);
功能:向内核注册一个信号处理函数
signum:信号编号
handler:函数指针,也可使用以下默认参数

SIG_IGN忽略该信号
SIG_DFL按默认方式处理

返回值
返回之前的信号处理方式

注意:
1、SIGKILL(9)、SIGSTOP(19)信号不能被捕获和忽略处理
2、当信号处理完后可能会返回产生信号的代码继续运行,如果我们捕获并处理段错误、算术异常等信号可能会产生死循环,正确的处理段错误、算数异常信号应该是备份数据并直接结束程序
3、有些系统通过signal注册的信号处理函数只能执行一次,如果想要持续有效,可以在信号处理函数中再重新注册一次
4、子进程会继承父进程的信号处理方式,但是通过exec系列函数创建的子进程,会恢复默认的信号处理方式

信号的发送方式

  1. 键盘
    Ctrl+c
    Ctrl+
    Ctrl+z 暂停\挂起 可以用fg命令使其继续运行

  2. 错误
    除零
    非法访问内存
    总线错误

  3. 命令
    kill -信号编号 进程号
    功能:向指定的进程发送信号
    killall -信号编号 进程名
    可以给同名进程发送同一个信号

  4. 函数
    int kill(pid_t pid, int sig);
    功能:向指定进程发送指定信号
    pid:进程号
    sig:信号编号

    int raise(int sig);
    功能:向进程自己发送信号sig

    void abort(void);
    功能:向进程自己发送信号SIGABRT

    unsigned int alarm(unsigned int seconds);
    功能:让内核在seconds秒后向进程发送SIGALRM信号
    返回值:上次alarm设置的剩余秒数

三、进程休眠信号

int pause(void)

功能:让调用者进入睡眠状态,直到进程遇到信号才会唤醒,相当于没有时间限制的sleep
返回值:要么不返回,要么唤醒后返回-1

unsigned int sleep(unsigned int seconds);
功能:让调用者进入休眠指定的秒数,当遇到信号时会提前唤醒返回
返回值:剩余的休眠时间

四、信号集和信号阻塞

信号集:是一种数据类型,定义的变量可以存储多个信号
sigset_t 128位的二进制数,每一位都固定代表了一种信号
相关函数
int sigemptyset(sigset_t *set);
功能:清空信号集
int sigfillset(sigset_t *set);
功能:填满信号集
int sigaddset(sigset_t *set, int signum);
功能:向信号集set中添加信号signum
int sigdelset(sigset_t *set, int signum);
功能:从信号集set中删除信号signum
int sigismember(const sigset_t *set, int signum);
功能:测试信号集中是否存在signum信号
返回值

0不存在
1存在
-1signum信号非法

信号阻塞
当程序执行到一些特殊操作时,不适合处理信号,此时可以让内核先屏蔽信号,等操作执行完成后再解除屏蔽重新发送信号。
递送:当信号产生时,内核会在其维护的信号表中为对应的进程设置与该信号对应的标记,这个过程叫做递送。
未决:从信号产生到完成递送有个时间间隔,处于这个间隔的信号状态称为未决。
信号屏蔽\阻塞就是让被屏蔽的信号先处于未决状态、暂停递送,当屏蔽解除时在继续递送。

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能:设置要屏蔽的信号、这些信号是存储在信号集里面
how:信号屏蔽的方式

SIG_BLOCK把set中的信号添加到要屏蔽的信号集里
SIG_UNBLOCK从信号屏蔽集中删除set中的信号 解除
SIG_SETMASK把set替换之前的信号屏蔽集

set:准备好的信号集
oldset:获取旧的信号屏蔽集,为了还原屏蔽集做的备份

五、附带数据信息的信号处理(较难)

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; //  信号屏蔽集
    int        sa_flags;//  信号处理动作标志
    SA_NODEFER 在信号处理过程中不要屏蔽当前信号
    SA_SIGINFO  使用 sa_sigaction 函数指针
    void     (*sa_restorer)(void); // 保留函数
};
     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;      /* 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 Linux 2.6.32) */
        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) */
        unsigned int si_arch;  /* Architecture of attempted system call
                                    (since Linux 3.5) */
    }

int sigqueue(pid_t pid,int sig, const union sigval value);
功能:向指定进程发送信号并附加信息一起发送
value:附加的信息

union sigval {
    int   sival_int; //  整数
    void *sival_ptr; //  指针
};

六、定时器

包含头文件#include <sys/time.h>

int getitimer(int which,struct itimerval *curr_value);
功能:获取当前的定时方案
which:选择使用的计时器

ITIMER_REAL真实计时器 程序总的计时时间
ITIMER_VIRTUAL虚拟计时器,在用户态的计时
ITIMER_PROF实际计时器 用户态+内核态计时, 会加上休眠时间,更精确

int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);
功能:设置定时器计时方案
which:选择使用的计时器

struct itimerval {
struct timeval it_interval;
// 每次时钟信号产生的间隔时间
struct timeval it_value;    
//  第一次产生时钟信号的时间
};

struct timeval {
    time_t      tv_sec;
    suseconds_t tv_usec;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值