linux系统编程---进程间的通讯---信号---学习和记录(四)

信号:信号(signal)是一种软件中断,是UNIX系统中最为古老的进程之间的通信机制。用于在一个或多个进程之间传递异步信号。它提供了一种处理异步事件的方法也是进程间惟一的异步通信方式。在Linux中,根据POSIX标准扩展以后的信号机制,不仅可以用来通知某种程序发生了什么事件,还可以给进程传递数据。

了解命令:                                                                                                                                       kill -l:查看系统中所有的信号;                                                                                        man 7 signal:查看系统中信号默认动作的定义;   

 

 *信号是从1号开始的,没有0号,32号,33号信号:在这些信号中,1~31号信号是普通信号,都是继承自UNIX系统,是不可靠信号,34~64号信号是实时信号,也称可靠信号

信号的处理方式:忽略,捕捉,和默认三种方式;

忽略信号:大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILL和SIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景。      

捕捉信号:告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理

系统默认动作:对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。   

signal函数:注册信号函数   

函数原型:

#include <signal.h>
typedef void (*sighandler_t)(int);//需要调用函数指针
sighandler_t signal(int signum, sighandler_t handler);

signum :信号的编号。
handler :中断函数的指针

函数例子:捕捉一些信号 SIGINT(2)   SIGUSR1(10)

#include<stdio.h>
#include <signal.h>
//真实处理信号的函数
void handler(int signum)
{
    printf("get signum=%d\n",signum);
    switch(signum){
        case 2:
            printf("SIGINT\n"); //按下 ctrl+c 会打印此行代码 
            break;
        case 10:
            printf("SIGUSR1\n"); //输入 kill -10 进程ID  会打印此行代码
            break;
    }
}
int main()
{
    signal(SIGINT,handler);//信号处理函数的注册
    signal(SIGUSR1,handler);//信号处理函数的注册
    while(1);
    return 0;
}

函数例子:用编程的方式实现 kill的功能 (一般杀死某个进程 采用 kill -9 进程ID )       kill()函数原型: int kill(pid_t pid,int sig);

#include<stdio.h>
#include <signal.h>
#include <sys/types.h>
int main(int argc,char **argv)
{
    int signum=0;
    int pid=0;
    //char cmd[128]={0};//配合system函数处理命令的大小
    signum= atoi(argv[1]);//输入的是char型 需要转为整型
    pid= atoi(argv[2]);//输入的是char型 转为整型
    printf("num=%d\n",signum);
    printf("pid=%d\n",pid); 	
    kill(pid,signum);
    // sprintf(cmd,"kill -%d %d",signum,pid);
    // system(cmd);
    printf("send signal ok\n");
    return 0;
}
输入 ./a.out 2 某个进程PID 可以杀死某个进程

补充上面sprintf()函数知识:将“kill -%d %d ” 都存放在cmd为char型的字符串里面 

sigaction函数:信号处理函数的注册(配置信号功能)

函数原型:

#include <signal.h>
int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);

//第二个参数是一个结构体,包含以下东西
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

//void (*sa_sigaction)(int, siginfo_t *, void *)里面siginfo_t结构体包含的东西
 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 */
       int      si_band;     /* Band event */
       int      si_fd;       /* File descriptor */
}

signum:参数指出要捕获的信号类型,也就是信号的编号
act:参数指定新的信号处理方式,struct sigaction类型如果不为空说明需要对该信号有新的配置。
oldact:备份,如果不为空,那么可以对之前的信号配置进行备份,以方便之后进行恢复,一般设置为NULL。

sigqueue函数:向指定进程发送一个信号和数据

函数原型:

#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);

//第三个参数是个联合体,包含的东西
union sigval {
       int   sival_int;
       void *sival_ptr;
};

pid:目标进程的进程号
sig:发的是什么信号,信号编号
value:发送的消息(int或者char*),是一个联合体,表示信号附带的数据,附带数据可以是一个整数也可以是一个指针

函数例子:

//信号处理函数的注册(配置信号功能)
#include<stdio.h>
#include <signal.h>
/*信号处理函数*/
void handler(int signum, siginfo_t *info, void *context)
{
    printf("get signum %d\n",signum);
    if(context!=NULL){//如果有内容
    printf("get data=%d\n",info->si_int);
    printf("get data=%d\n",info->si_value.sival_int);
}
int main()
{
    struct sigaction act;
    printf("pid = %d\n",getpid());
    act.sa_sigaction = handler;//信号处理程序,能够接受额外数据和sigqueue配合使用
    act.sa_flags = SA_SIGINFO;//影响信号的行为SA_SIGINFO表示能够接受数据
    sigaction(SIGUSR1,&act,NULL);
    //sigaction(SIGINT,&act,NULL);
    while(1);
    return 0;
}

//运行后阻塞
//向指定进程发送一个信号和数据
#include <signal.h>
#include <stdio.h>
int main(int argc,char **argv)
{
     int pid = atoi(argv[2]);
     int signum = atoi(argv[1]);
     union sigval value;
     value.sival_int = 100;
     sigqueue(pid,signum,value);//信号处理发送函数
     return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值