11、信号(1)

1、进程调用kill函数将任一信号发送给另一进程或进程组。当信号出现可以告诉内核以3种方式处理:(1)忽略信号;(2)捕捉信号,kill默认发送的是SIGTERM终止信号,不能捕获SIGKILL和SIGSTOP信号;(3)执行系统默认动作,“终止+core”表示在进程当前工作目录的core文件中复制了该进程的内存映像。大多数UNIX系统调试程序都使用core文件检查进程终止时的状态。

2、signal函数,ISO C定义,不涉及多进程、进程组、终端IO等,对UNIX系统没什么用处。

#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
//void (*signal(int xx))(int);(*signal(int xx))返回的是一个函数指针,该指针指向的函数无返回值
#include "apue.h"
static void sig_usr(int);

int main(void)
{
    //SIGUSR1,SIGUSR2为UNIX系统中用户可自定义处理的信号
        if(signal(SIGUSR1, sig_usr)==SIG_ERR)
                err_sys("can't catch SIGUSR1");
        if(signal(SIGUSR2, sig_usr)==SIG_ERR)
                err_sys("can't catch SIGUSR2");
        for(;;)
                pause();
}

static void sig_usr(int signo)
{
        if(signo == SIGUSR1)
                printf("received SIGUSR1\n");
        else if(signo == SIGUSR2)
                printf("received SIGUSR2\n");
        else
                err_dump("received signal %d\n",signo);
}
john@ubuntu16:~/apue/mysig$ ./a.out &
[1] 14981
//向进程发送信号
john@ubuntu16:~/apue/mysig$ kill -USR1 14981
received SIGUSR1
john@ubuntu16:~/apue/mysig$ kill -USR2 14981
received SIGUSR2

一个进程在调用fork时,子进程继承父进程的信号处理方式。因为子进程在开始时复制了父进程内存映像,所以信号捕捉函数的地址在子进程中是有意义的。一个进程在执行一个新程序后,就不能捕捉了,因为信号捕捉函数的地址很可能在新程序文件中无意义。

3、不可重入函数
在信号处理操作期间会阻塞任何引起不一致的信号发送。不可重入包括:a、使用静态数据结构;b、调用malloc或free;c、标准IO函数,标准IO库的很多实现都以不可重入的方式使用全局数据结构。

4、可靠信号术语和语义
事件可以是硬件异常(如除以0)、软件条件(如alarm定时器超时)、终端产生的信号或kill函数。每个进程都有一个信号屏蔽字,它规定了当期那要阻塞递给该进程的信号集。对于每一种可能的信号,该屏蔽字中都有一位与之对应。

5、kill和raise函数,raise允许进程向自身发送信号
对于非root用户,发送者的实际用户ID或有效用户ID必须等于接受者的实际用户ID或有效用户ID。POSIX.1把编号为0定义为空信号,如果signo为0,则确定特定进程是否存在。

//raise(signo) == kill(getpid(),signo)
int kill(pid_t pid, int signo);
//如果pid等于0,则把信号发给同组所有进程,不包括系统进程(内核进程和init进程)
int raise(int signo);

6、alarm和pause函数
alarm函数设置一个定时器,超时则产生SIGALRM信号,如果忽略或不捕获该信号,默认动作是终止调用该alarm函数的进程。每个进程只能有一个闹钟时间。如果在调用alarm时,之前已为该进程注册的闹钟时间还没超时,则该闹钟时间的余值作为本次alarm函数调用的值返回。之前注册的闹钟时间被新值代替。

unsigned int alarm(unsigned int seconds);
int pause(void);//使进程挂起直到捕捉到一个信号

7、信号集,告诉内核不允许发生该信号集中的信号

int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);

int sigismember(const sigset_t *set, int signo);

8、sigprocmask,该函数仅为单线程定义的。处理多线程进程中信号使用另一个函数。

//屏蔽信号,只是不处理该信号,信号并未消失
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
//oset返回之前信号集
//how=SIG_SETMASK,则把set设为当前信号集
//how=SET_BLOCK 当前信号集并上set
//how=SET_UNBLOCK 当前信号集交set

9、sigpending

//返回被挂起的信号集
int sigpending(sigset_t *set);
//通过set返回信号集

10、sigaction函数取代了早期的signal

//oact返回之前的动作
int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact)

struct sigaction{
    void (*sa_handler)(int);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_sigaction)(int, siginfo_t *, void *);
}
//如果sa_flags=SA_SIGINFO,则sa_sigaction为代替信号处理程序
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值