进程间通信

作者: cpp加油站 | 来源:发表于2018-08-09 11:48 被阅读3次

    1.信号

    信号是比较复杂的通信方式,用于通知接收进程有某种事情发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信息语义函数signal外,还支持语义符合Posix 1标准的信号函数sigaction。

    • signal() 告诉系统内核怎么处理该信号
    • sigaction() 也是处理信号,但比signal更健壮
    • kill() 发送信号
    • alarm() 经过预定时间后发送SIGALARM信号

    2.mmap文件映射:

    也是一种共享内存,但是它是直接映射到磁盘中具体的文件,会涉及到磁盘的读写和io占用,不如shm共享内存效率高,但因为它的实际存储并没有反映到内存上,可以申请比较大的存储空间。

    3.管道及有名管道

    管道可用于具有亲缘关系进程间的通信,例如父子进程,但是有名管道允许无关系的进程间通信。管道其实就是建立一个FIFO文件,一个进程往里面写数据,另外的进程读取数据。
    demo如下:

        #include <stdio.h>
        #include <unistd.h>
        #include <string.h>
        #include <sys/wait.h>
        #include <stdlib.h>
    
        void sys_err(const char *str)
        {
            perror(str);
            exit(1);
        }
    
        int main()
        {
            pid_t pid;
            char buf[1024];
            int fd[2];
            char *p = "test for pipe\n";
            if (pipe(fd) == -1)
                sys_err("pipe");
    
            pid = fork();
            if (pid < 0) 
            {
                sys_err("fork err");
            }
            else if(pid == 0)
            {
                //父进程   
                close(fd[1]);
                int len = read(fd[0], buf, sizeof(buf));
                write(STDOUT_FILENO, buf, len);  //输出到屏幕
                close(fd[0]);
            }
            else
            {
                //子进程
                close(fd[0]);
                write(fd[1], p, strlen(p)); //写入test for pipe
                wait(NULL);
                close(fd[1]);
            }
    
            return 0;
        }
    

    4.消息队列

    消息队列也叫报文队列,消息队列是消息的链接表,包括Posix消息队列和SystemV消息队列,有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的信息,消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
    发送消息demo如下:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>

    struct my_msg_st
    {
        long int my_msg_type;
        char some_text[BUFSIZ];
    };
    
    int main(void)
    {
        int running = 1;
        struct my_msg_st some_data;
        int msgid = 0;
        char buffer[BUFSIZ] = {0};
        memset((void*)&some_data, 0, sizeof(some_data));
    
        /*创建消息队列*/
        msgid=msgget((key_t)1234,0666 | IPC_CREAT);
        if(msgid==-1)
        {
            fprintf(stderr,"msgget failed with error:%d\n",errno);
            exit(EXIT_FAILURE);
        }
    
        /*循环向消息队列中添加消息*/
        while(running)
        {
            memset(buffer, 0, sizeof(buffer));
            printf("Enter some text:");
            fgets(buffer,BUFSIZ,stdin);
            some_data.my_msg_type=1;
            strcpy(some_data.some_text,buffer);
    
            /*添加消息*/
            if(msgsnd(msgid,(void *)&some_data,BUFSIZ,0)==-1)
            {
                fprintf(stderr,"msgsed failed\n");
                exit(EXIT_FAILURE);
            }
    
            /*用户输入的为“end”时结束循环*/
            if(strncmp(buffer,"end",3)==0)
            {
                running=0;
            }
        }
        exit(EXIT_SUCCESS);
    }
    接收消息demo如下:
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    
    struct my_msg_st
    {
        long int my_msg_type;
        char some_text[BUFSIZ];
    };
    
    int main(void)
    {
        int running=1;
        int msgid = 0;
        struct my_msg_st some_data;
        long int msg_to_receive=0;
        memset((void*)&some_data, 0, sizeof(some_data));
    
        /*创建消息队列*/
        msgid=msgget((key_t)1234,0666 | IPC_CREAT);
        if(msgid==-1)
        {
            fprintf(stderr,"msgget failed with error: %d\n",errno);
            exit(EXIT_FAILURE);
        }
        
        /*循环从消息队列中接收消息*/
        while(running)
        {
            /*读取消息*/
            if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0)==-1)
            {
                fprintf(stderr,"msgrcv failed with error: %d\n",errno);
                exit(EXIT_FAILURE);
            }
    
            printf("接收到的消息为: %s",some_data.some_text);
    
            /*接收到的消息为“end”时结束循环*/
            if(strncmp(some_data.some_text,"end",3) == 0)
            {
                running=0;
            }
        }
    
        /*从系统内核中移走消息队列*/
        if(msgctl(msgid,IPC_RMID,0) == -1)
        {
            fprintf(stderr,"msgctl(IPC_RMID) failed\n");
            exit(EXIT_FAILURE);
        }
        exit(EXIT_SUCCESS);
    }
    

    5.共享内存
    共享内存是一种文件映射,使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其他通信机制,如信号量结合使用,来达到进程间的同步及互斥。
    demo如下:
    写入共享内存:

    #include<stdlib.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include<string.h>
    #include<errno.h>
    
    typedef struct _Teacher
    {
        char name[64];
        int age;
    }Teacher;
    
    int main(int argc, char *argv[])
    {
        int ret = 0;
        int    shmid = 0;
        //创建共享内存 ,相当于打开文件,文件不存在则创建
        shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT | 0666); 
        if (shmid == -1)
        {
            perror("shmget err");
            return errno;
        }
        printf("shmid:%d \n", shmid);
        Teacher *p = NULL;
        //将共享内存段连接到进程地址空间
        p = (Teacher*)shmat(shmid, NULL, 0);//第二个参数shmaddr为NULL,核心自动选择一个地址
        if (p == (void *)-1 )
        {
            perror("shmget err");
            return errno;
        }
        strcpy(p->name, "aaaa");
        p->age = 33;
        //将共享内存段与当前进程脱离
        shmdt(p);
            
        printf("键入1 删除共享内存,其他不删除\n");
        
        int num = 0;
        scanf("%d", &num);
        if (num == 1)
        {
            //用于控制共享内存
            ret = shmctl(shmid, IPC_RMID, NULL);//IPC_RMID为删除内存段
            if (ret < 0)
            {
                perror("rmerrr\n");
            }
        }                 
    
        return 0;    
    }
    从共享内存读取:
    
    #include<stdio.h>
    #include <unistd.h>
    #include<stdlib.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include<string.h>
    #include<errno.h>
    
    typedef struct _Teacher
    {
        char name[64];
        int age;
    }Teacher;
    
    int main(int argc, char *argv[])
    {
        int ret = 0;
        int    shmid = 0;
        //打开获取共享内存
        shmid = shmget(0x2234, 0, 0); 
        if (shmid == -1)
        {
            perror("shmget err");
            return errno;
        }
        printf("shmid:%d \n", shmid);
        Teacher *p = NULL;
        //将共享内存段连接到进程地址空间
        p = (Teacher*)shmat(shmid, NULL, 0);
        if (p == (void *)-1 )
        {
            perror("shmget err");
            return errno;
        }
        
        printf("name:%s\n", p->name);
        printf("age:%d \n", p->age);
        //将共享内存段与当前进程脱离
        shmdt(p);
        
        printf("键入1 程序暂停,其他退出\n");
        
        while(1)
        {
            sleep(1);
        }       
        return 0;
    }
    

    6.socket
    socket也就是套接字,最普遍的进程间通信机制,可用于不同机器之间的进程间通信,具体见网络编程。

    相关文章

      网友评论

        本文标题:进程间通信

        本文链接:https://www.haomeiwen.com/subject/wpuqbftx.html