[领卓教育]linux进程通信机制——信号(SIGNAL)

1.信号
1) 是在软件层次上对中断机制的一种模拟,异步通信
2)可以直接进行用户空间进程和内核进程之间交互,内核进程也可以利用它来通知用户空间
进程发生了哪些系统事件。
3)如果该进程当前并未处于执行态,则该信号就由内核保存起来,知道该进程恢复执行再传递给他;
如果一个信号被进程设置为阻塞,则该信号的传递被延迟,知道阻塞取消时才被传递给进程。
2.系统定义的信号 (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
信号从1 到31 是系统早期定义的信号, 不实时信号
信号从34 到64 后期补充的信号, 是实时信号

3.用户进程对信号的响应方式:
忽略信号:对信号不做任何处理。
捕捉信号:定义信号处理函数,当信号发生时,执行相应的处理函数。
但是有两个信号不能处理不能忽略:即SIGKILL及SIGSTOP。
4. 执行缺省操作:Linux对每种信号都规定了默认操作
SIGHUP :默认行为 : 杀死, 该信号在用户终端连接(正常或非正常)结束时发出
SIGINT :默认行为 : 杀死 该信号在用户键入INTR字符(通常是Ctrl+C)时发出,终端驱动程序发送此信号并送到前台进程中的每一个进程。
SIGQUIT:默认行为 : 杀死, 该信号和SIGINT类似,但由QUIT字符(通常是Ctrl + )来控制。
SIGKILL:默认行为 : 杀死, 不能捕捉也不能被忽略
SIGALRM:默认行为 : 杀死 , 定时时间到发出
SIGSTOP:默认行为 : 暂停,不能捕捉也不能被忽略
SIGTSTP: 默认行为 : 暂停, 可以被捕捉可忽略,(通常是Ctrl-Z)发出这个信号。
SIGCHLD: 默认行为 : 忽略,子进程改变状态时,父进程会收到这个信号
SIGUSR1 :默认行为 :杀死 用户可以使用的信号,
SIGUSR2 :默认行为 :杀死 用户可以使用的信号,

练习1:编写一段程序,使用系统调用fork( )创建两个子进程,再用系统调用signal( )
让父进程捕捉键盘上来的中断信号(即按ctrl+c键 SIGINT),当捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发出信号,子进程捕捉到父进程发来的信号后,分别输出下列信息后终止:
Child process 1 is killed by parent!
Child process 2 is killed by parent!
父进程等待两个子进程终止后,输出以下信息后终止:
Parent process exit!

结果:
child2 is running !
child1 is running !
child2 is running !
child1 is running !
child2 is running !
child1 is running !
^Cchild2 is killed by parent !
child1 is killed by parent !
parent is exit

代码:

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

pid_t pid_child1,pid_child2 ;//定义两个进程号用来保存子进程的pid
void stop(int signum)
{
    if(signum == SIGINT)//捕捉到由父进程接收到的Ctrl+c信号
    {
        //给两个子进程发送信号
        kill(pid_child1,SIGUSR1) ;
        kill(pid_child2,SIGUSR2) ;
    }
    if(signum == SIGUSR1)//子进程1捕捉到由父进程发送的SIGUSR1信号
    {
        printf("child1 is killed by parent !\n") ;
        exit(0) ;
    }
    if(signum == SIGUSR2)//子进程2捕捉到由父进程发送的SIGUSR2信号
    {
        printf("child2 is killed by parent !\n") ;
        exit(0) ;
    }
}

int main(int argc, const char *argv[])
{
    pid_t pid ;
    pid = fork() ;
    if(pid < 0)
    {
        perror("fork") ;
        exit(-1) ;
    }
    else if(pid == 0)//子进程1
    {
        signal(SIGINT,SIG_IGN) ;//子进程忽略Ctrl+c信号
        signal(SIGUSR1,stop) ;//用户自定义信号,处理stop函数
        while(1)
        {
            printf("child1 is running !\n") ;
            sleep(1) ;
        }
    }
    else
    {
        pid_child1 = pid ;//用pid_child1保存父进程返回的子进程1的pid
        pid = fork() ;
        if(pid < 0)
        {
            perror("fork2") ;
            exit(-1) ;
        }
        else if(pid == 0)//子进程2
        {
            signal(SIGINT,SIG_IGN) ;//子进程忽略Ctrl+c信号
            signal(SIGUSR2,stop) ;//用户自定义信号,处理stop函数
            while(1)
            {
                printf("child2 is running !\n") ;
                sleep(1) ;
            }
        }
        else //parent
        {
            pid_child2 = pid ;//保存父进程返回的子进程2的pid
            signal(SIGINT,stop) ;
            signal(SIGCHLD,stop) ;
            /************等待两个子进程都退出后***************/
            /************父进程执行相应动作*******************/
            waitpid(pid_child1,NULL,0) ;
            waitpid(pid_child2,NULL,0) ;
            printf("parent is exit\n") ;
            exit(0) ;
        }
    }
    return 0;
}

练习2:
司机售票员问题
创建子进程代表售票员,父进程代表司机 ,同步过程如下:
售票员捕捉SIGINT(代表开车)(父进程忽略这个信号),发SIGUSR1给司机,司机打印(“let’s gogogo”)
售票员捕捉SIGQUIT(代表停车)(父进程忽略这个信号),发SIGUSR2给司机,司机打印(“stop the bus”)
司机捕捉SIGTSTP(代表车到总站)(子进程忽略这个信号),发SIGUSR1给售票员,售票员打印(“please get off the bus”)

结果:
^CLet`s go go go !
^Zplease get off the bus !
^\stop the bus !

代码:

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

pid_t pid_child ;

void sighandler_child(int signum) 
{
    if(signum == SIGINT)
    {
        kill(getppid(),SIGUSR1) ;
    }
    if(signum == SIGQUIT)
    {
        kill(getppid(),SIGUSR2) ;
    }
    if(signum == SIGUSR1)
    {
        printf("please get off the bus !\n") ;
    }
}
void sighandler_parent(int signum)
{
    if(signum == SIGUSR1)
    {
        printf("Let`s go go go !\n") ;
    }

    if(signum == SIGUSR2)
    {
        printf("stop the bus !\n") ;
        exit(0) ;
    }
    if(signum == SIGTSTP)
    {
        kill(pid_child,SIGUSR1) ;
    }
}
int main(int argc, const char *argv[])
{
    pid_t pid ;
    pid = fork();
    if (pid < 0)
    {
        perror("fork") ;
        exit(-1) ;
    }
    else if(pid == 0)  //child1
    {
        signal(SIGINT,sighandler_child) ; //售票员接收信号
        signal(SIGQUIT,sighandler_child) ; //售票员接收信号
        signal(SIGTSTP,SIG_IGN) ; //售票员忽略到站
        signal(SIGUSR1,sighandler_child) ;
        while(1) ;
    }
    else //parent 
    {
        pid_child = pid ;
        signal(SIGINT,SIG_IGN) ; //忽略Ctrl + c
        signal(SIGUSR1,sighandler_parent) ;
        signal(SIGQUIT,SIG_IGN) ; //忽略Ctrl + '\'
        signal(SIGUSR2,sighandler_parent) ;
        signal(SIGTSTP,sighandler_parent) ; //到站 Ctrl + z
        waitpid(pid_child,NULL,0) ;
    }
    return 0 ;
}

总结:linux通信机制中信号与信号灯是两种通信方式,
System V的信号灯又被称为信号量,是不同进程间或一个给定进程内部不同线程间同步的机制。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值