进程间通信IPC _信号

本文章为个人学习笔记,其中的内容参考了其他文章以及自己学习中的理解而做的笔记,所以此笔记是可参考 可借鉴 可指点;其中有些内容可能解释得不是那么正确等问题,望参考者多查其他资料,防止带偏!


信号

为 Linux 提供了一种处理异步事件的方法。即中断。

信号处理的三种方式:忽略(其中SIGKILL、SIGSTOP不能被忽略)、捕捉、默认系统的动作。

查看系统中所有信号可以在终端输入 kill -l 来查看,发现信号的编号是从1开始的,一共64个。

PU@Embed_Learn:~/IPC$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

其中 9) SIGKILL 为杀死进程 ; 2) SIGINT 为CTRL + c 中断进程

当需要杀死某个进程时,可以在终端输入  ps aux|grep ./a.out  来查看a.out 进程的ID

然后在输入 kill -9 进程ID


信号之 signal 的函数原型

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);


对于sighandler_t signal(int signum, sighandler_t handler)函数来说,signum 是信号的编号,handler 是中断函数的指针,为修改后真实执行该捕捉信号的动作。
typedef void (*sighandler_t)(int)中断函数后执行的动作,参数 int 为捕捉的信号类型,在中断函数中来判断是捕捉到哪一个信号,而来确定哪一个信号该执行哪一个的修改的信号动作

 信号的捕捉示例

左边运行时,左边捕捉 ctrl +c 的信号,

默认动作应该是输入ctrl+c就会退出循环,但是这个程序被修改成捕捉该信号并执行handler内的内容,则该信号就不会执行系统默认动作了

  右边运行后,两边的结果

 将上面的右边程序中的kill用sprintf和system代替,效果一样,执行./a.out 9 ID

#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>

// typedef void (*sighandler_t)(int);

// sighandler_t signal(int signum, sighandler_t handler);

//int kill(pid_t pid, int sig);

//int sprintf(char *str, const char *format, ...);

int main(int argc,char **argv)
{
        int signum;
        int pid;
        char cmd[128]={0};

        printf("atoi before:argv[1] signum=%s,argv[2] pid=%s!\n",argv[1],argv[2]);

        signum=atoi(argv[1]);
        pid=atoi(argv[2]);

        printf("atoi after:signum=%d,pid=%d!\n",signum,pid);

        //      kill(pid,signum);

        sprintf(cmd,"kill -%d %d",signum,pid);
        system(cmd);
        printf("system signal kill ok !\n");

        return 0;
}

其中用到两个新的函数

atoi 

atoi() 函数用来将字符串转换成整数(int),其原型为:
int atoi (const char * str);

【函数说明】atoi() 函数会扫描参数 str 字符串,跳过前面的空白字符(例如空格,tab缩进等,可以通过 
isspace() 函数来检测),直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回。

【返回值】返回转换后的整型数;如果 str 不能转换成 int 或者 str 为空字符串,那么将返回 0。

温馨提示:ANSI C 规范定义了 
stof()atoi()atol()strtod()strtol()strtoul() 共6个可以将字符串转换为数字的函数,大家可以对比学习。另外在 C99 / C++11 规范中又新增了5个函数,分别是 atoll()、strtof()、strtold()、strtoll()、strtoull() 。

sprintf

sprintf()函数用于将格式化的数据写入字符串,其原型为:

int sprintf(char *str, char * format [, argument, ...]);

【返回值】成功则返回参数str 字符串长度,失败则返回-1,错误原因存于errno 中。

【参数】str为要写入的字符串;format为格式化字符串,与printf()函数相同;argument为变量。

除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数--格式化字符串--上。 printf()和sprintf()都使用格式化字符串来指定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的字符串。

sprintf()最常见的应用之一莫过于把整数打印到字符串中,如:
sprintf(s, "%d", 123);  //把整数123打印成一个字符串保存在s中
sprintf(s, "%8x", 4567);  //小写16进制,宽度占8个位置,右对齐


信号另一版本 sigaction

#include <signal.h>

收信号
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

发信号
int sigqueue(pid_t pid, int sig, const union sigval value);

(其中所涉及的结构体,联合体等都是头文件所包含了的,可直接使用其中的参数)

其中一些收信号sigaction的参数含义及用法
sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

1.int signum 是信号编号,或者名称 eg:SIGUSR1,SIGINT……等

2.const struct sigaction *act 是结构体变量,如下

回调函数句柄sa_handler、sa_sigaction只能任选其一,如果选择第一种就和前面信号singal类似的功能。
struct sigaction {
    void (*sa_handler)(int); 
    //信号处理程序,不接受额外数据,SIG_IGN 为忽略,SIG_DFL 为默认动作
   
    void (*sa_sigaction)(int, siginfo_t *,void *); 
    //信号处理程序,能够接受额外数据和sigqueue配合使用
   
    sigset_t sa_mask;
    //阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。一般可以不设置该参数。
    
    int sa_flags;//影响信号的行为SA_SIGINFO表示能够接受数据
};

其中sa_sigaction函数中参数
signum 信号编号   void *context 判断是否等于NULL,等于代表没有数据
结构体中的参数如下(使用时选其中一种即可)
siginfo_t {
int      si_signo;    /* Signal number */
int      si_errno;    /* An errno value */
int      si_code;     /* Signal code */
int      si_trapno;   /* Trap number that caused hardware-generated signal
                                        (unused on most architectures) */
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) */
}
3.struct sigaction *oldact 一般设置为NULL
其中发信号sigqueue函数的参数及用法如下

int sigqueue(pid_t pid, int sig, const union sigval value);


其中的参数如下
pid 为接收方的进程ID
sig 为之间的信号编号
const union sigval value 联合体

union sigval {
               int   sival_int;//发送整数数据
               void *sival_ptr;//发送字符串
           };


简单图例解释

先上代码吧

 运行结果如下

 信号注意事项

  1. 使用 sigaction 函数安装信号处理程序时,制定了 SA_SIGINFO 的标志。
  2. sigaction 结构体中的 sa_sigaction 成员提供了信号捕捉函数。如果实现的时 sa_handler 成员,那么将无法获取额外携带的数据。

其中

sigqueue 函数只能把信号发送给单个进程,可以使用 value 参数向信号处理程序传递整数值或者指针值。

sigqueue 函数不但可以发送额外的数据,还可以让信号进行排队,对于设置了阻塞的信号,使用 sigqueue 发送多个同一信号,在解除阻塞时,接受者(代码内部可使用循环等手段来达到此功能)会接收到发送的信号队列中的信号。信号不能无限的排队,信号排队的最大数量值就会受到SIGQUEUE_MAX的限制,达到最大限制后,sigqueue 会失败,errno 会被设置为 EAGAIN。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值