• linux学习笔记之进程间通信


    一、基础知识。

    1:进程通信基础(interProcess Communication, IPC):管道,FIFO(命名管道),XSI IPC,POSIX 信号量。

    2:管道。

      1,缺陷。

        1)部分系统支持全双工(不确定linux)

        2)管道只能在具有公共祖先的两个进程之间使用。

      2,相关函数。

      3,协同进程:一个过滤程序既产生某个过滤程序的输入,又读取该过滤程序的输出。

    3:FIFO。

      1,作用:能够使 不相关的进程 进行通信。

      2,一些注意点。

        1)FIFO路径名存在于文件系统中。

      3,一些用途。

        1)shell命令使用FIFO将数据从一条管道传送到另外一条。无需创建中间文件。

        2)C/S模式中,FIFO用作汇聚点,在客户进程和服务器进程之间传递数据。

    4:XSI IPC。

      1,有三种:消息队列,信号量,共享储存器。

      2,使用 非负整数 的标识符。数据类型为: key_t <sys/types.h>

      3,有多种方法使 客户进程 和服务器进程 在同一IPC结构上汇聚。

        1)服务器进程指定键IPC_PROVATE创建新IPC结构,并将标识符存放在某处,让客户进程取用。

        2)在公共头文件中定义一个 两个进程 都认可的键。

        3)两个进程 认可一个路径名和项目ID使用ftok函数将两个值变成一个KEY。

      4,基本问题。

        1)IPC结构在系统范围内起作用,没有引用计数。

        2)IPC结构在文件系统中没有名字。

        3)IPC不能使用文件描述符,所以不能对它们使用多路转接IO函数。

      5,消息队列:消息的链接表。

      6,信号量:一个计数器。用于为多个进程提供对共享数据对象的访问。

        1)信号量通常在内核中实现。且减1操作为原子操作。

        2)进程终止时,内核会自动检测信号量,并进行调整。

        3)互斥量比信号量快很多。但如果可能尽量使用信号量。因为信号量的心痛支持度较高,而且复杂性更低。

      7,共享存储:最快的IPC。

        1)信号量可用于同步共享储存访问。

    5:POSIX 信号量。

      1,相对XSI优点。

        1)更高性能。

        2)使用更简单:没有信号量集,部分操作统一化。

        3)信号量删除表现的更完美:直到最后一次使用后才释放。

      2,拥有两种性是:命名的和未命名的。差异:创建和销毁的形式上。

      3,为增加移植性,信号量命名应该有一定规则:

        1)第一个字符为 斜杠 / 。

        2)名字不包含其他斜杠以避免实现定义的行为。

        3)信号量名最大长度由实现定义。

      4,P470 客户进程-服务器进程属性。

    二、相关函数。

    1:管道。

    1 创建管道。
      int pipe( int fd[2] );
      // 1 fd[0]为读 fd[1]为写。fd[1]的输出是fd[0]的输入。
    2 创建一个管道,fork一个子进程,关闭未使用的管道端,执行一个shell命令,等待命令终止。
      // !!!需要进一步了解者两个函数原理和使用机制!!!
      FILE *popen( cosnt char *cmdstring, const char *type );  // fork --> exec and cmd --> return a ptr of IO.
      int pclose( FILE *fp );
      // 适用于简单的过滤器程序

     2:FIFO:命名管道。

    #include <sys/stat.h>
    1 创建FIFO
      int mkfifo( const char *path, mode_t mode );
      int mkfifoat( int fd, const char *path, mode_t mode );
      // 1 一般情况下,都是阻塞到读写开始为止。但设置非阻塞时,会立即返回-1,errno设置ENXIO。

     3:XSI IPC

    1 通过路径名+项目ID产生一个KEY。
      key_t ftok( const char *path, int id );
      // 1 参数path必须引用现有文件,参数id只使用低8位。
    2 ipc_perm 权限和所有者.
      struct ipc_perm
      {
        uid_t   uid;    // owner's effective user id.
        gid_t   gid;    // owner's effective group id.
        uid_t   cuid;   // creator's effective user id.
        gid_t   cgid;   // creator's effective group id.
        mode_t  mode;   // access modes
      }  // 此为最小结构。具体实现 可添加成员
    3 消息队列的信息结构 msqid_ds。
      struct msqid_ds
      {
        struct ipc_perm      msg_perm;   // see section.
        msgqnum_t            msg_qnum;   // # of messages on queue.
        msglen_t             msg_qbytes; // max # of bytes on queue.
        pid_t                msg_lspid;  // pid of last msgsnd()
        pid_t                msg_lrpid;  // pid of last msgrcv()
        time_t               msg_stime;  // last-msgsnd() time
        time_t               msg_rtime;  // last-msgrcv() time
        time_t               msg_ctime;  // last-change time
      }
    4 打开/创建 一个队列。
      int msgget( key_t key, int flag );
    5 对 队列 执行多种操作。
      int msgctl( int msqid, int cmd, struct msqid_ds *buf );
      // 1 参数cmd:IPC_STAT, IPC_SET, IPC_RMID
    6 将数据放到消息队列中。
      int msgsnd( int msqid, cosnt void *ptr, size_t nbytes, int flag );
      // 1 参数ptr:指向mymesg结构。
    7 从队列取消息。
      ssize_t megrcv( int msqid, void *ptr, size_t nbytes, long type, int flag );
      // 1 参数type:>0时,以非 先进先出 的次序 获取消息。
    8 获取一个信号量。
      int semget( key_t key, int nsems, int flag );
    9 多种信号量操作。
      int semctl( int semid, int semnum, int cmd, .../* union semun arg */ );
      // 1 参数cmd:IPC_STAT,IPC_SET,IPC_RMID,GETVAL...
    10 自动执行信号量集合上的操作数组。
      int semop( int semid, struct sembuf semoparray[], size_t nops );   // 具有原子性,或者执行所有,或者全部不执行。
      struct sembuf
      {
        unsigned short    sum_num;   // member # in set (0, 1, ..., nsems-1)
        short             sem_op;    // operation(negative, 0, or pasitive )
        short             sem_flg;   // IPC_NOWAIT, SEM_UNDO
      }
    11 内核为每个共享储存段维护一个结构。
      struct shmid_ds
      {
        struct ipc_perm  shm_perm;   // see section
        size_t           shm_segsz;  // size of segment in bytes
        pid_t            shm_lpid;   // pid of last shmop
        pid_t            shm_cpid;   // pid of creator
        shmatt_t         shm_nattch; // number of current attaches
        time_t           shm_atime;  // last-attach time
        time_t           shm_dtime;  // last-detach time
        time_t           shm_ctime;  // last-change time
        ...
      }
    12 获得一个共享储存标示符。
      int shmget( key_t key, size_t size, int flag );
      // 1 参数size:字节为单位。通常为系统页长的整倍数。
    13 对共享存储 执行多种操作。
      int shmctl( int shmid, int cmd, struct shmid_ds *buf );
      // 1 参数cmd:IPC_STAT,IPC_SET,IPC_RMID,SHM_LOCK,SHM_UNLOCK
    14 将共享存储连接到进程中。
      void shmat( int shmid, cosnt void *addr, int flag );
    15 进程和共享存储的分离操作(不删除共享存储)。
      int shmdt( const void *addr );

    4:POSIX 信号量。

    1 创建信号量 / 使用现有信号量。
      sem_t sem_open( const char *name, int oflag, mode_t mode, unsinged int value );
    2 释放信号量相关资源。
      int sem_close( sem_t *sem );
    3 销毁一个命名信号量。
      int sem_unlink( const char *name );  // 当最后一个引用关闭时 才销毁。
    4 实现信号量减一操作。
      int sem_trywait( sem_t *sem );
      int sem_wait( sem_t *sem );
      int sem_timedwait( sem_t *sem, const struct timespec *restrict tsptr );
      // 1 资源为0时,发生阻塞。>0,减一
    5 信号量+1
      int sem_post( sem_t *sem );
    6 创建/销毁 一个未命名信号量。
      int sem_init( sem_t *sem, int pshared, unsigned int value );
      int sem_destroy( sem_t *sem );
    7 检索信号量值。
      int sem_getvalue( sem_t *restrict sem, int *restrict valp );
      // 1 除非使用额外的同步机制来避免竞争,否则此函数只能用于调试

    三、

  • 相关阅读:
    docker学习笔记(一)-vagrant/docker machine安装docker,阿里云通过docker machine安装docker
    docker安装 centos7
    Robot Framework user guide
    Powershell 备忘
    如何在linux系统内用openssl 生成 过期的证书
    同时装了Python3和Python2,怎么用pip?
    python 基础笔记三
    python 基础笔记二
    python对文件的操作
    3-4 字典的嵌套
  • 原文地址:https://www.cnblogs.com/zheng39562/p/4270243.html
Copyright © 2020-2023  润新知