zoukankan      html  css  js  c++  java
  • 【系统编程】 进程间通信方式

    1.管道pipe:

      利用管道进行父子进程间通信:

      

       利用管道进行父子间双向通信:

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #define BUF_SIZE 20
    int main(int argc,char *argv[]){
        int fd[2],fd1[2];
        char buf[BUF_SIZE];
        pipe(fd);pipe(fd1);
        pid_t pid = fork();
        if(pid==0){
            char str[] = "Hello world\n";
            write(fd[1],str,sizeof(str));
            int len = read(fd1[0],buf,BUF_SIZE);
            write(STDOUT_FILENO,buf,len);
        }   
        else{
            sleep(1);
            char str[] = "zytxdy\n";
            write(fd1[1],str,sizeof(str));
            int len = read(fd[0],buf,BUF_SIZE);
            write(STDOUT_FILENO,buf,len);
        }   
        sleep(1);
        return 0;
    }
    View Code

    2.有名管道FIFO:
    创建方法:1.直接mkfifo  FIFONAME 创建有名管道。

          

         2.在.c里写代码创建,头文件包括sys/stat.h,参数1是名称,参数2是权限  

                         

     实现无血缘间进程的通信:

      其实FIFO和文件打开关闭相似性大,与管道pipe其实关联性并不大,FIFO可以一个写端多个读端/多个写端一个读端。

      /*注意以下代码运行的时候要加参数,参数即为FIFO名*/

      写端write:

    #include<stdio.h>
    #include<unistd.h>
    #include<sys/stat.h>
    #include<sys/types.h>
    #include<fcntl.h>
    #include<stdlib.h>
    #include<string.h>
    
    int main(int argc,char *argv[]){
        int fd,i;
        char buf[4096];
    
        fd = open(argv[1],O_WRONLY);
        i=0;
        while(1){
            sprintf(buf,"hello itcast: %d\n",i++);
    
            write(fd,buf,strlen(buf));
            sleep(1);
        }
        close(fd);
        return 0;
    }
    View Code

      读端read:

    #include<stdio.h>
    #include<unistd.h>
    #include<sys/stat.h>
    #include<sys/types.h>
    #include<fcntl.h>
    #include<stdlib.h>
    #include<string.h>
    
    int main(int argc,char *argv[]){
        int fd,len;
        char buf[4096];
    
        fd = open(argv[1],O_RDONLY);
        int i=0;
        while(1){
            len = read(fd,buf,sizeof(buf));
            write(STDOUT_FILENO,buf,len);
            sleep(1);
        }
        close(fd);
        return 0;
    }
    View Code

    3.共享存储映射:

      1.文件直接用于通信(由于比较简单就略过)

      2.存储映射I/O(mmap:Memory map):

      

      

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<unistd.h>
    #include<error.h>
    #include<pthread.h>
    #include<sys/mman.h>
    #include<fcntl.h>
    int main(int argc,char *argv[]){
        char *p = NULL;
        int fd;
        fd = open("testmap",O_RDWR|O_CREAT|O_TRUNC,0644);
        
        lseek(fd,20,SEEK_END);   //扩展文件大小
        write(fd,"\0",1);
    
        int len = lseek(fd,0,SEEK_END); //获取文件大小
       
        p = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); //可读可写,p为字符串形式文件内容
        if(p == MAP_FAILED){
            perror("mmap error");
            exit(1);
        }
        //使用 p 对文件进行读写操作
        strcpy(p,"Hello mmap"); //写操作
    
        printf("-----%s\n",p);
    
        int ret = munmap(p,len);
        if(ret == -1){
            perror("munmap error");
            exit(1);
        }
        return 0;
    }
    View Code

     

    4.信号集操作函数:

       

      set会与阻塞信号集做或操作

      

      

        

       示例代码:

    #include<stdio.h>
    #include<stdlib.h>
    #include<signal.h>
    #include<unistd.h>
    #include<errno.h>
    void print_set(sigset_t *set){
        for(int i=1; i<32 ;i++){
            if(sigismember(set,i))
                putchar('1');
            else
                putchar('0');
        }
        printf("\n");
    }
    
    int main(int argc,char *argv[]){
        sigset_t set,oldset,pedset;
        int ret = 0;
    
        sigemptyset(&set);
        sigaddset(&set,SIGINT);
    
        ret = sigprocmask(SIG_BLOCK,&set,&oldset);
        if(ret == -1){
            perror("sigprocmask error");
            exit(1);
        }
    
        while(1){
            ret = sigpending(&pedset);
            if(ret == -1){
                perror("sigpending error");
                exit(1);
            }
    
            print_set(&pedset);
            sleep(1);
        }
        return 0;
    }
    View Code

       如下所示,按下<ctrl+c>组合键就能看到位发生了变化,因为其在未决信号集之中

       

     ps:注意,kill -9即使被屏蔽了也照样生效,其他的被屏蔽了就无法生效。

    5.信号:

       阻塞信号集(信号屏蔽字):将某些信号加入集合,对他们设置屏蔽,当屏蔽x信号后,再收到该信号,该信号的处理将推后(解除屏蔽后)

       未决信号集:

        1.信号产生,未决信号集中描述该信号的位立刻为1,表示信号处于未决状态。当信号被处理对应位反转为0。这一时刻往往非常短暂。

        2.信号产生后由于某些原因(主要是阻塞)不能抵达。这类信号的集合称为未决信号集。在屏蔽解除前,信号一直处于未决状态。

      信号4要素:

        信号编号、信号名称、信号对应事件、信号默认处理动作    

        信号使用之前,应先确定其4要素,而后再用。

          

        默认动作:

          Term:终止进程

          lgn:忽略信号(默认即时对该种信号忽略操作)

          Core:终止进程,生成Core文件。(查验进程死亡原因,用于gdb调试)

          Stop:停止(暂停)进程

          Cont:继续运行进程

       硬件异常产生信号:

        除0操作 -> 8)SIGFPE(浮点数例外)

        非法访问内存 -> 11)SIGSEGV(段错误)

        总线错误  -> 7)SIGBUS

    信号捕捉:

      signal函数:

    #include<stdio.h>
    #include<signal.h>
    #include<unistd.h>
    void sig_catch(int signo){
        printf("catch you! %d\n",signo);
        return ;     
    }
    int main(int argc,char *argv[] ){
         signal(SIGINT,sig_catch);        
         while(1);  
    }
    View Code

          这时候编译运行后,一旦输入<ctrl+c>组合键,就会显示捕捉到信号  

      

       sigaction函数:

      也是用来注册一个信号的捕捉函数

    #include<stdio.h>
    #include<signal.h>
    #include<unistd.h>
    void sig_catch(int signo){        //步骤函数,回调函数
        printf("catch you! %d\n",signo);
        return ;     
    }
    int main(int argc,char *argv[] ){
         struct sigaction act,oldact;
    
         act.sa_handler = sig_catch; //设置捕捉的函数名
         sigemptyset(&act.sa_mask);//初始化,设置屏蔽字mask
         act.sa_flags = 0;                 //默认属性
    
         sigaction(SIGINT,&act,&oldact);        
         while(1);  
    }
    View Code

      当然我们也可以捕捉很多函数,如下图所示即可捕捉2个信号:

      

       信号捕捉特性:

        1:捕捉函数执行期间,信号屏蔽字,由mask -->sa_mask,捕捉函数执行结束,恢复回mask

        2:捕捉函数执行期间,本信号自动被屏蔽(sa_flags = 0)

        3:捕捉函数执行期间,被屏蔽信号多次发送,解除屏蔽后只处理一次

        

    前ICPC算法竞赛退役选手|现摸鱼ing
  • 相关阅读:
    文本内容超长显示省略号,鼠标移上自动显示全部内容(适用于EasyUI DataGrid)
    Spring注入静态变量的方法,以及CXF如何获取客户端IP
    Agile PLM 表结构说明
    session_start() failed: .......No space left on device问题解决
    如何配置sublime xdebug进行远程调试
    宝塔面板for linux
    Ubuntu 16.04下ssh启用root登录
    mysql- Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'
    表单重复提交、大并发库存超卖?面试官提出了一个老生常谈的问题,让我陷入了沉思...
    ubuntu16.04 wordpress建站教程
  • 原文地址:https://www.cnblogs.com/Anonytt/p/15560669.html
Copyright © 2011-2022 走看看