zoukankan      html  css  js  c++  java
  • 进程间通信系列 之 信号综合实例

     进程间通信系列 之 概述与对比   http://blog.csdn.net/younger_china/article/details/15808685
     进程间通信系列 之 共享内存及其实例   http://blog.csdn.net/younger_china/article/details/15961557
     进程间通信系列 之 共享内存简单实例   http://blog.csdn.net/younger_china/article/details/15991081
     进程间通信系列 之 信号(理论)   http://blog.csdn.net/younger_china/article/details/15976961
     进程间通信系列 之 信号实例   http://blog.csdn.net/younger_china/article/details/15968715
     进程间通信系列 之 信号综合实例   http://blog.csdn.net/younger_china/article/details/15980485
     进程间通信系列 之 命名管道FIFO及其应用实例   http://blog.csdn.net/younger_china/article/details/15808531
     进程间通信系列 之 管道(客户端和服务端通信)   http://blog.csdn.net/younger_china/article/details/15809281
     进程间通信系列 之 信号量详解及编程实例   http://blog.csdn.net/younger_china/article/details/15808531
     进程间通信系列 之 消息队列函数及其范例   http://blog.csdn.net/younger_china/article/details/15503871
     进程间通信系列 之 消息队列应用实例   http://blog.csdn.net/younger_china/article/details/15808501 
     进程间通信系列 之 socket套接字及其实例  
    http://blog.csdn.net/younger_china/article/details/15809163
     进程间通信系列 之 socket套接字实例   http://blog.csdn.net/younger_china/article/details/15809207


    原文地址:进程间通信--信号(进程间通信唯一的异步方式) 作者:Deem_passion

    一、信号的介绍


    信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。

    信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了那些系统事件。

    如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递个它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞取消时才被传递给进程。

    二、linux操作系统支持的信号

    A. kill  -l


    B.常用信号的含义



    三、信号的产生

    A.用户在终端按下某些键时,终端驱动程序会发送信号给前台进程,例如ctr+c产生SIGINT,  ctr + 产生SIGQUI信号,ctr + z产生SIGTSTP。

    B.硬件异常产生信号,这些条件由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给当前进程 。

    C.一个进程调用int kill(pid_t pid,int sig)函数可以给另一个进程发送信号

    D.可以用kill命令给某个进程发送信号,如果不明确指定信号则发送SIGTERM信号,该信号的默认处理动作是终止进程。

    E.当内核检测到某种软件条件发生时也可以通过信号通知进程,例如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号。

    四、进程对信号的处理

    A.忽略此信号
    B.执行该信号的默认处理动作
    C.提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式成为捕捉(Catch)一个信号。
     

    五、相关信号API

    A.通过系统调用向一个指定的进程发送信号



    参数说明:
    第一个参数:指定发送信号的接收线程
    第二个参数:信号的signum

    案例一、
    父进程从终端输入signum,然后发给子进程

    #include <stdio.h>
    #include <sys/types.h>
    #include <signal.h>
    #include <stdlib.h>
    
    int main()
    {
        int pid;
    
        if((pid = fork()) < 0)
        {
        
            perror("Fail to fork");
            exit(EXIT_FAILURE);
        
        }else if(pid == 0){
            
            while(1);
        
        }else{
            
            int signum;
            
            while(scanf("%d",&signum) == 1)
            {
                kill(pid,signum);
                system("ps -aux | grep a.out");
            }
        }
    
        return 0;
    }
    


    运行结果如下:

    B.捕捉一个信号

    对应的API


    其原型:

    我们一般都是用第一个,也就是通过typedef改写过的。

    注意:signal函数我一般认为其是向内核注册当前进程收到信号的处理的方式。
    signal(SIGINT,handler);


    参数说明:

    signum  :  指定信号
    handler  :  SIG_IGN忽略该信号,SIG_DFL采用系统默认方式处理信号,自定义的信号处理函数指针。

    案例探究:

    通过异步方式,给子进程收尸

    注意:子进程在终止时会给父进程发SIGCHLD,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需要专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。
    <span style="font-size:12px;">#include <stdio.h>
    #include <signal.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    void child_exit_handler(int signum)
    {
        if(signum == SIGCHLD)
        {
            printf("Child exit.
    ");
            wait(NULL);
        }
    }
    
    int main()
    {
        int pid;
        int i = 0;
    
        //想内核注册,处理 SIGCHLD信号的方式
        signal(SIGCHLD,child_exit_handler);
    
        if((pid = fork()) < 0)
        {
            perror("Fail to fork");
            exit(EXIT_FAILURE);
    
        }else if(pid == 0){
            
            for(i = 0;i < 5;i ++)
            {
                printf("child loop.
    ");
                sleep(1);
            }
        
        }else{
            
            for(i = 0;i < 5;i ++)
            {
                printf("Father loop.
    ");
                sleep(2);
            }
    
        }
    
        exit(EXIT_SUCCESS);
    }</span>
     
    C.闹钟函数alarm


    larm()也称为闹钟函数,它可以在进程中设置一个定时器。当定时器指定的时间到时,内核就向进程发送SIGALARM信号。

    seconds:指定的秒数,如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。

    成功:如果调用此alarm()前,进程中已经设置了闹钟时间,则放回上一个闹钟时间的剩余时间,否则返回0。

    alarm(100);
    ........

    ......

    alarm(5);

    出错:-1

    案例探究:
    <span style="font-size:12px;">#include <stdio.h>
    #include <signal.h>
    #include <stdlib.h>
    
    void handler(int signum)
    {
        if(signum == SIGALRM)
        {
            printf("Recv SIGALARM.
    ");
        }
    
        exit(EXIT_SUCCESS);
    }
    
    int main()
    {
        int count = 0;
        int n = 0;
    
        signal(SIGALRM,handler);
    
        n = alarm(10);
    
        printf("n = %d.
    ",n);
        
        sleep(2);
    
        n = alarm(5);
    
        printf("n = %d.
    ",n);
        
        while(1)
        {
            printf("count = %d.
    ", ++count);
            sleep(1);
        }
    
        return 0;
    }</span>
    运行结果如下:




    案例二、综合案例

    使用FIFO实现clientA与clientB之间聊天
    A.输入quit后,两个进程退出
    B.如果在20秒内,没有等到另一端发来的消息,则认为对方已不在,此时终止。

    clientA:
    <span style="font-size:12px;">#include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <string.h>
    #include <fcntl.h>
    
    #define MAX 100
    
    void signal_handler(int signum)
    {
        static int flag = 0;
    
        switch(signum)
        {
            case SIGALRM:
                if(flag == 0)
                {
                    printf("The people is leaving,the system is closed in 10 seconds 
                            and you can input 'ctrl + c' cancel.
    ");
                    alarm(10);
                }else{
                    
                    kill(getppid(),SIGKILL);
                    usleep(500);
                    exit(EXIT_SUCCESS);
                }
    
                flag = 1;            
                break;
    
            case SIGINT:
                printf("The alarm is cancel.
    ");
                alarm(0);
                break;
        }
    
    }
    
    int child_recv_fifo(char *fifo_name)
    {
        int n,fd;
        char buf[MAX];
    
        if((fd = open(fifo_name,O_RDONLY)) < 0)
        {
            fprintf(stderr,"fail to open %s : %s.
    ",fifo_name,strerror(errno));
            return -1;
        }
    
        signal(SIGALRM,signal_handler);
        signal(SIGINT,signal_handler);
        alarm(15);//璁剧疆瀹氭椂鍣?    
        while(1)
        {
            n = read(fd,buf,sizeof(buf));
            buf[n] = '';
    
            printf("Read %d bytes : %s.
    ",n,buf);
    
            if(strncmp(buf,"quit",4) == 0 || n == 0)
            {
                kill(getppid(),SIGKILL);
                usleep(500);
                exit(EXIT_SUCCESS);
            }
    
            alarm(15);
        }
    
        return 0;
    }
    
    int father_send_fifo(char *fifo_name,int pid)
    {
        int n,fd;
        char buf[MAX];
    
        if((fd = open(fifo_name,O_WRONLY)) < 0)
        {
            fprintf(stderr,"Fail to open %s : %s.
    ",fifo_name,strerror(errno));
            return -1;
        }
    
        signal(SIGINT,SIG_IGN);
    
        while(1)
        {
            getchar();
            printf(">");
    
            fgets(buf,sizeof(buf),stdin);
            buf[strlen(buf)-1] = '';
    
            write(fd,buf,strlen(buf));
    
            if(strncmp(buf,"quit",4) == 0)
            {
                kill(pid,SIGKILL);
                usleep(500);
                exit(EXIT_SUCCESS);
            }
        }
    
        return 0;
    }
    
    int main(int argc,char *argv[])
    {
        int pid;
    
        if(argc < 3)
        {
            fprintf(stderr,"usage %s argv[1].
    ",argv[0]);
            exit(EXIT_FAILURE);
        }
    
        if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
        {
            perror("Fail to mkfifo");
            exit(EXIT_FAILURE);
        }
    
        if(mkfifo(argv[2],0666) < 0 && errno != EEXIST)
        {
            perror("Fail to mkfifo");
            exit(EXIT_FAILURE);
        }
        
        if((pid = fork()) < 0)
        {
        
            perror("Fail to fork");
            exit(EXIT_FAILURE);
        
        }else if(pid == 0){
            
            child_recv_fifo(argv[2]);
        
        }else{
    
            father_send_fifo(argv[1],pid);
        }
    
        exit(EXIT_SUCCESS);
    }</span>

    client B

    <span style="font-size:12px;">#include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <string.h>
    #include <fcntl.h>
    
    #define MAX 100
    
    void signal_handler(int signum)
    {
        static int flag = 0;
    
        switch(signum)
        {
            case SIGALRM:
                if(flag == 0)
                {
                    printf("The people is leaving,the system is closed in 10 seconds 
                            and you can input 'ctrl + c' cancel.
    ");
                    alarm(10);
                }else{
                    
                    kill(getppid(),SIGKILL);
                    usleep(500);
                    exit(EXIT_SUCCESS);
                }
    
                flag = 1;            
                break;
    
            case SIGINT:
                printf("The alarm is cancel.
    ");
                alarm(0);
                break;
        }
    
    }
    
    int child_recv_fifo(char *fifo_name)
    {
        int n,fd;
        char buf[MAX];
    
        if((fd = open(fifo_name,O_RDONLY)) < 0)
        {
            fprintf(stderr,"fail to open %s : %s.
    ",fifo_name,strerror(errno));
            return -1;
        }
    
        signal(SIGALRM,signal_handler);
        signal(SIGINT,signal_handler);
        alarm(15);//璁剧疆瀹氭椂鍣?    
        while(1)
        {
            n = read(fd,buf,sizeof(buf));
            buf[n] = '';
    
            printf("Read %d bytes : %s.
    ",n,buf);
    
            if(strncmp(buf,"quit",4) == 0 || n == 0)
            {
                kill(getppid(),SIGKILL);
                usleep(500);
                exit(EXIT_SUCCESS);
            }
    
            alarm(15);
        }
    
        return 0;
    }
    
    int father_send_fifo(char *fifo_name,int pid)
    {
        int n,fd;
        char buf[MAX];
    
        if((fd = open(fifo_name,O_WRONLY)) < 0)
        {
            fprintf(stderr,"Fail to open %s : %s.
    ",fifo_name,strerror(errno));
            return -1;
        }
    
        signal(SIGINT,SIG_IGN);
    
        while(1)
        {
            getchar();
            printf(">");
    
            fgets(buf,sizeof(buf),stdin);
            buf[strlen(buf)-1] = '';
    
            write(fd,buf,strlen(buf));
    
            if(strncmp(buf,"quit",4) == 0)
            {
                kill(pid,SIGKILL);
                usleep(500);
                exit(EXIT_SUCCESS);
            }
        }
    
        return 0;
    }
    
    int main(int argc,char *argv[])
    {
        int pid;
    
        if(argc < 3)
        {
            fprintf(stderr,"usage %s argv[1].
    ",argv[0]);
            exit(EXIT_FAILURE);
        }
    
        if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)
        {
            perror("Fail to mkfifo");
            exit(EXIT_FAILURE);
        }
    
        if(mkfifo(argv[2],0666) < 0 && errno != EEXIST)
        {
            perror("Fail to mkfifo");
            exit(EXIT_FAILURE);
        }
        
        if((pid = fork()) < 0)
        {
        
            perror("Fail to fork");
            exit(EXIT_FAILURE);
        
        }else if(pid == 0){
            
            child_recv_fifo(argv[1]);
        
        }else{
    
            father_send_fifo(argv[2],pid);
        }
    
        exit(EXIT_SUCCESS);
    }
    </span>


     

    
  • 相关阅读:
    分享15款为jQuery Mobile定制的插件
    显​示​器​分​辨​率​调​高​后​黑​屏​的​最​佳​解​决​办​法
    out 和 ref 之间的区别整理
    赋值操作符重载
    最长公共子串
    最长递增子序列
    动态规划
    Eclipse支持Jquery代码提示(JqeuryWTP)
    ubuntu10.04编译内核不显示grub菜单解决
    CSS水平导航条和纵向导航条
  • 原文地址:https://www.cnblogs.com/youngerchina/p/5624522.html
Copyright © 2011-2022 走看看