zoukankan      html  css  js  c++  java
  • Linux进程间通信

    0. 前言

       进程是一个独立的资源管理单元,不同进程间的资源是独立的,不能在一个进程中访问另一个进程的用户空间和内存空间。但是,进程不是孤立的,不同进程之间需要信息的交互和状态的传递,因此需要进程间数据的传递、同步和异步的机制。

        当然,这些机制不能由哪一个进程进行直接管理,只能由操作系统来完成其管理和维护,Linux提供了大量的进程间通信机制,包括同一个主机下的不同进程和网络主机间的进程通信,如下图所示:
    mark

    • 同主机间的信息交互
    • 无名管道
      特点:多用于亲缘关系进程间通信,方向为单向;为阻塞读写;通信进程双方退出后自动消失
      问题:多进程用同一管道通信容易造成交叉读写的问题
    • 有名管道
      FIFO(First In First Out),方向为单向(双向需两个FIFO),以磁盘文件的方式存在;通信双方一方不存在则阻塞
    • 消息队列
      可用于同主机任意多进程的通信,但其可存放的数据有限,应用于少量的数据传递
    • 共享内存
      可实现同主机任意进程间大量数据的通信,但多进程对共享内存的访问存在着竞争
    • 同主机进程间同步机制:信号量(Semaphore)
    • 同主机进程间异步机制:信号(Signal)
    • 网络主机间数据交互:Socket(套接字)

    1. 共享内存 - 概念

    mark
    共享内存,主要是实现进程间大量数据的传输。所谓共享内存,即在内存中开辟一段特殊的内存空间,多个进程可互斥访问,该内存空间具有自身特有的数据结构。
    共享内存的数据结构如下 - struct shmid_ds

    /*  Come from /usr/include/linux/shm.h  */
    
    /* Obsolete, used only for backwards compatibility and libc5 compiles */
    struct shmid_ds {
        struct ipc_perm     shm_perm;   /* operation perms */
        int                 shm_segsz;  /* size of segment (bytes) */
        __kernel_time_t     shm_atime;  /* last attach time */
        __kernel_time_t     shm_dtime;  /* last detach time */
        __kernel_time_t     shm_ctime;  /* last change time */
        __kernel_ipc_pid_t  shm_cpid;   /* pid of creator */
        __kernel_ipc_pid_t  shm_lpid;   /* pid of last operator */
        unsigned short      shm_nattch; /* no. of current attaches */
        unsigned short      shm_unused; /* compatibility */
        void                *shm_unused2;   /* ditto - used by DIPC */
        void                *shm_unused3;   /* unused */
    };
    
    

    多个进程在使用此共享内存空间时候,必须在进程地址空间与共享内存地址空间之间建立连接,即将共享内存空间挂载到进程中;
    共享内存是由一个进程开辟,其它任何进程都可以挂载;
    共享内存并不会随着进程的退出而消失,因此最后不使用此内存空间时,必须要手动删除

    2. 共享内存管理

    1). 创建共享内存 - shmget

    • 作用
      创建一个共享内存空间

    • 头文件

        #include <sys/shm.h>
      
    • 函数原型

        int shmget(key_t key, size_t size, int shmflg)
      
    • 参数

    • key: ftok()的返回值
    • size: 想要创建的共享内存的大小 (字节)
    • shmflg: 共享内存段的创建标识
    Macro No. Description Head File
    IPC_CREAT 01000 若key内存段不存在,则创建;否则返回内存首地址 /usr/include/linux/ipc.h
    IPC_EXCL 02000 若key内存段存在,则返回错误
    IPC_NOWAIT 04000 不等待直接返回
    shm_r 0400 可读 /usr/include/linux/shm.h
    shm_w 0200 可写 /usr/include/linux/shm.h
    • 返回值
      成功:共享内存空间的标志 shm_id
      失败:-1

    2). 共享内存控制 - shmctl

    • 作用
      对共享内存进程操作,包括:读取/设置状态,删除操作

    • 头文件

        #include<sys/shm.h>
      
    • 函数原型

        int shmctl(int shmid, int cmd, struct shmid_ds *buf)
      
    • 参数

    • shmid : shmget()返回值
    • buf:临时共享内存变量信息
    • cmd :
    Macro No. Description Return
    IPC_RMID 0 删除 0
    IPC_SET 1 设置 ipc_perm 参数 0
    IPC_STAT 2 获取 ipc_perm 参数
    IPC_INFO 3 ipcs命令
    SHM_LOCK 11 锁定共享内存段 0
    SHM_UNLOCK 12 解锁共享内存段 0
    • 返回值
      成功:
      失败:-1

    3). 共享内存映射 - shmat()

    • 作用
      将共享内存空间挂载到进程中

    • 头文件

        #include <sys/shm.h>
      
    • 函数原型

        void *shmat(int shmid, const void *shmaddr, int shmflg)
      
    • 参数

    • shmid : shmget()返回值
    • shmaddr: 共享内存的映射地址,一般为0(由系统自动分配地址)
    • shmflg : 访问权限和映射条件
    Macro No. Descripton Remind
    - 0 默认有读写权限 常用
    SHM_RDONLY 010000 只读
    SHM_RDN 020000 Round attach address to SHMLBA boundary
    SHM_REMAP 040000 take-over region on attach
    • 返回值
      成功:共享内存段首地址
      失败:NULL / (void *)-1

    4). 共享内存分离 - shmdt()

    • 作用
      将进程与共享内存空间分离 (只是与共享内存不再有联系,并没有删除共享内存)

    • 头文件

         #include <sys/shm.h>
      
    • 函数原型

        int shmdt(const void *shmaddr)
      
    • 参数

    shmaddr:共享内存的首地址

    • 返回值
      成功: 0
      失败: -1

    3. 示例代码:

    mark
    两个进程通过共享内存传输数据,因共享内存不可同时读写,因此采用二元信号量进行进程互斥,具体操作如下:

    • init: 设置信号量为0,此时只允许写入,不允许读取(因为共享内存没有数据);
    • Sender: 在sem=0时,写入数据到共享内存(阻塞读);写入完成后,sem=1,此时可以读取,不可以写入;
    • Receiver: 在sem=1时,读取数据;读取完成后,sem=0,此时只允许写入。

    1- Sender.c

    /*
     * Filename: Sender.c
     * Description: 
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/sem.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/types.h>
    #include <string.h>
    
    int main(int argc, char *argv[])
    {
        key_t  key;
        int shm_id;
        int sem_id;
        int value = 0;
    
        //1.Product the key
        key = ftok(".", 0xFF);
    
        //2. Creat semaphore for visit the shared memory
        sem_id = semget(key, 1, IPC_CREAT|0644);
        if(-1 == sem_id)
        {
            perror("semget");
            exit(EXIT_FAILURE);
        }
    
        //3. init the semaphore, sem=0
        if(-1 == (semctl(sem_id, 0, SETVAL, value)))
        {
            perror("semctl");
            exit(EXIT_FAILURE);
        }
    
        //4. Creat the shared memory(1K bytes)
        shm_id = shmget(key, 1024, IPC_CREAT|0644);
        if(-1 == shm_id)
        {
            perror("shmget");
            exit(EXIT_FAILURE);
        }
    
        //5. attach the shm_id to this process
        char *shm_ptr;
        shm_ptr = shmat(shm_id, NULL, 0);
        if(NULL == shm_ptr)
        {
            perror("shmat");
            exit(EXIT_FAILURE);
        }
    
        //6. Operation procedure
        struct sembuf sem_b;
        sem_b.sem_num = 0;      //first sem(index=0)
        sem_b.sem_flg = SEM_UNDO;
        sem_b.sem_op = 1;           //Increase 1,make sem=1
        
        while(1)
        {
            if(0 == (value = semctl(sem_id, 0, GETVAL)))
            {
                printf("
    Now, snd message process running:
    ");
                printf("	Input the snd message:  ");
                scanf("%s", shm_ptr);
    
                if(-1 == semop(sem_id, &sem_b, 1))
                {
                    perror("semop");
                    exit(EXIT_FAILURE);
                }
            }
    
            //if enter "end", then end the process
            if(0 == (strcmp(shm_ptr ,"end")))
            {
                printf("
    Exit sender process now!
    ");
                break;
            }
        }
    
        shmdt(shm_ptr);
    
        return 0;
    }
    
    

    2- Receiver.c

    /*
     * Filename: Receiver.c
     * Description: 
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/sem.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/types.h>
    #include <string.h>
    
    int main(int argc, char *argv[])
    {
        key_t  key;
        int shm_id;
        int sem_id;
        int value = 0;
    
        //1.Product the key
        key = ftok(".", 0xFF);
    
        //2. Creat semaphore for visit the shared memory
        sem_id = semget(key, 1, IPC_CREAT|0644);
        if(-1 == sem_id)
        {
            perror("semget");
            exit(EXIT_FAILURE);
        }
    
        //3. init the semaphore, sem=0
        if(-1 == (semctl(sem_id, 0, SETVAL, value)))
        {
            perror("semctl");
            exit(EXIT_FAILURE);
        }
    
        //4. Creat the shared memory(1K bytes)
        shm_id = shmget(key, 1024, IPC_CREAT|0644);
        if(-1 == shm_id)
        {
            perror("shmget");
            exit(EXIT_FAILURE);
        }
    
        //5. attach the shm_id to this process
        char *shm_ptr;
        shm_ptr = shmat(shm_id, NULL, 0);
        if(NULL == shm_ptr)
        {
            perror("shmat");
            exit(EXIT_FAILURE);
        }
    
        //6. Operation procedure
        struct sembuf sem_b;
        sem_b.sem_num = 0;      //first sem(index=0)
        sem_b.sem_flg = SEM_UNDO;
        sem_b.sem_op = -1;           //Increase 1,make sem=1
        
        while(1)
        {
            if(1 == (value = semctl(sem_id, 0, GETVAL)))
            {
                printf("
    Now, receive message process running:
    ");
                printf("	The message is : %s
    ", shm_ptr);
    
                if(-1 == semop(sem_id, &sem_b, 1))
                {
                    perror("semop");
                    exit(EXIT_FAILURE);
                }
            }
    
            //if enter "end", then end the process
            if(0 == (strcmp(shm_ptr ,"end")))
            {
                printf("
    Exit the receiver process now!
    ");
                break;
            }
        }
    
        shmdt(shm_ptr);
        //7. delete the shared memory
        if(-1 == shmctl(shm_id, IPC_RMID, NULL))
        {
            perror("shmctl");
            exit(EXIT_FAILURE);
        }
    
        //8. delete the semaphore
        if(-1 == semctl(sem_id, 0, IPC_RMID))
        {
            perror("semctl");
            exit(EXIT_FAILURE);
        }
    
        return 0;
    }
    
    
  • 相关阅读:
    JDBC编程获取数据库连接(mysql 8.0版本以上)
    opnet启动和debug模式提示warning:找不到目录
    打开Word时默认使标题下的内容折叠起来
    OPNET进程编译器无法编译:Compilation failed || VS2017或VS2019与opnet的安装注意
    IDEA中使用单元测试方法@Test
    C/C++字符数组、字符串、字符串指针、字符串指针数组的访问操作(一维数组)
    C/C++字符数组、字符串、字符串指针、字符串指针数组的声明和初始化操作(一维数组)
    安装C++集成开发环境CodeBlock(带MinGW)
    Express
    模块化
  • 原文地址:https://www.cnblogs.com/Jimmy1988/p/7706980.html
Copyright © 2011-2022 走看看