zoukankan      html  css  js  c++  java
  • Apue.15 IPC

    对于CS的课程,除了离散数学和编译原理这种抽象程度较高的理论课,其他的基本都要自己动手写代码、观察和调试的,这里的读书笔记其实没啥大用,只是作为一个督促自我学习的方式,同时也算是以后方便查询的index吧。马上就要开学,华为的习题还没做,今天开始添加此项任务吧。

    IPC方式,POSIX.1规定的有pipe和FIFO;XSI扩展中又添加了消息队列、信号量和共享内存,以及网络编程中的套接字;XSI可选部分规定了STREAMS流机制。

    管道:

    最古老的IPC方式,POSIX.1规定的是半双工,某些系统提供全双工实现。

    只能在具有公共祖先的进程间使用,创建:

    #include <unistd.h>

    int pipe(int fields[2]);    //fields[0]为读端口,fields[1]为写端口;

    管道是文件,可以用S_ISFIFO来判断,fstat对管道的每一端都返回一个FIFO类型的文件描述符;

    常见用法:pipe创建管道,fork创建子进程;在父进程中关闭fd[0],在子进程中关闭fd[1];父进程用于写,子进程用于读;或者反着来,子进程写父进程读;

    更常见的用法:直接复制文件描述符为对应的标准输入/输出;

    若管道的一端关闭,规则:

    写读端已关闭的管道,产生信号SIGPIPE,返回-1,errno=EPIPE;

    读写端已关闭的管道,正常;若读取完毕,read返回0,表示到达文件尾端;

    常量PIPE_BUF规定了管道缓冲区的大小,若write的字节数大于该常量,那么,可能会造成多个同时写该管道(或FIFO)的进程之间出现穿插。

    管道可用于父子进程之间的同步,简单来说,创建两条管道(TELL_WAIT),然后等待(read);完成操作后发送(write);

    由于复制为标准I/O的用法太过常见,因此标准库直接提供了更简单的函数:

    #include <stdio.h>

    FILE *popen(const char *cmdstring, const char *type);    //type=r,w,表示为读|写而打开管道;分别将其标准输出|输入连接到文件指针;

    int pclose(FILE *fp);        //关闭I/O流,返回shell结束状态

    popen会先fork然后exec参数中的程序,返回打开文件的指针。

    popen绝不应该由setuid | setgid的程序调用;

    popen特别适用于构造简单的过滤器程序。

    协同进程

    当一个程序产生某个过滤程序的输入,同时又读取该过滤程序的输出,则称之为该过滤程序的协同程序。

    通常采用两个管道实现协同程序。注意标准I/O对于管道是全缓冲机制的。

    FIFO

    又称为命名管道,与管道的最大不同在于可以由非公共祖先的进程共同使用。

    FIFO类似于普通文件,不同进程之间通过援引文件名来使用FIFO。创建:

    #include <sys/stat.h>

    int mkfifo(const char *pathname, mode_t mode);

    mode的参数和创建文件时权限的参数相同;一旦创建FIFO完毕,其使用方法类似于pipe和普通文件。

    常见用法:FIFO用于客户进程—服务器进程之间的通信,客户进程通过众所周知的FIFO向服务器进程发送read请求,服务器进程通过各自的FIFO响应客户进程;

    XSI IPC

    XSI IPC都通过"标识符"加以引用,IPC标识符一般是long类型的整数,其外部名被称为key,共享IPC数据结构的方案:

    1. 服务器进程在使用创建IPC的函数时,指定key=IPC_PRIVATE用于创建一个新IPC结构,将返回的标识符存放在一个文件中以便客户进程取用,
    2. 在一个公用的头文件中指定key,然后服务器用此key创建结构。缺点是可能已经被占用了。
    3. 指定一个路径名和项目ID(0~255),使用ftok生成key(注意路径名必须现实存在)。注意:如果使用同一ID,那么key可能重复;

    创建IPC的函数有相同的结构(msgget, semget, shmget),第一个参数是key,第二个则是flag;

    创建新IPC的方法:key=IPC_PRIVATE,或flag中指定IPC_CREAT(最好同时指定IPC_EXCL,防止打开了一个已创建的同名IPC结构)。

    权限结构,所有XSI IPC中都有一个结构成员来限制IPC的权限:

    struct ipc_perm{

        uid_t uid;    //owner's uid

        gid_t gid;    //owner's gid

        uid_t cuid;    //creator's uid

        gid_t cgid;    //creator's gid

        mode_t mode;//access mode

    };

    除了不可执行外,mode与普通文件的访问权限一致;

    XSI IPC的主要缺点是没有访问计数,必须显式删除;其二是这些IPC结构在文件系统中没有名字,这意味着必须创建一系列的系统调用来完成对IPC对象的处理;

    消息队列

    每则消息由三部分组成:type(unsigned long),length(unsigned, bytes)和实际的消息。

    struct msqid_ds{

        struct ipc_perm msg_perm;    //权限控制

        msgnum_t msg_qnum;        //队列中消息

        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

    };

    相关限制:消息最长字节|队列的最大字节等;

    处理函数:

    #include <sys/msg.h>

    int msgget(key_t key,int flag);//返回消息ID或-1

    int msgctl(int msqid, int cmd, struct msqid_ds *buf);//垃圾桶函数,cmd=IPC_STAT(取队列的msqid_ds结构,存放在buf中),IPC_SET(设置该队列的),IPC_RMID(删除该消息队列和数据)

    int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);//flag可指定IPC_NOWAIT(无阻塞)

    int msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);//type指定消息类型,type=0返回第一条消息;type<0则返回队列中消息类型值小于或等于type绝对值的消息(取最小的一个)

    信号量

    semaphore 是一种计数器,用来对可用资源进行计数。理论上说,很简单:

    如果资源可用,那么信号量的值>0,每使用一个资源,信号量-1;

    如果资源不可用,那么信号量=0,进程休眠等待;当信号量>0时,进程被唤醒;

    如果进程不再使用资源,那么释放,信号量+1.

    信号量集:

    struct semid_ds{

        struct ipc_perm sem_perm;

        unsigned short sem_nsems;

        time_t sem_otime;

        time_t sem_ctime;

    };

    信号量:

    struct{

        unsigned short semval;

        pid_t sempid;

        unsigned short semncnt;

        unsigned short semzcnt;

    };

    #include <sys/sem.h>

    int semget(key_t key, int nsems, int flag);

    int semctl(int semid, int semnum, int cmd,… /* union semun arg */);

    union semun{

        int val;

        struct semid_ds *buf;

        unsigned short *array;

    };

    除了和msg类似的3个cmd外,还有一系列用于获取参数的cmd(GETVAL,GETPID等);

    int semop(int semid, struct sembuf semoparray[], size_t nops);

    struct sembuf{

        unsigned short sem_num;    //信号集中的信号序数

        short sem_op;            //操作(加减)

        short sem_flag;        //IPC_NOWAIT, SEM_UNDO

    };

    SEM_UNDO存在的意义在于可以在exit后内核可以自己处理信号量,进行收尾工作。

    一般而言,使用记录锁可以完成的任务,最好不要使用更为复杂的信号量;

    共享内存

    最快的IPC,回忆进程的内存空间结构,共享内存在stack的地址前,heap的地址后(向上增长)。内核实际链接的共享存储段放在进程的什么位置和系统明确相关。

    使用共享存储需要注意多个进程之间的访问同步问题。

    各种处理函数和flag与前面两种IPC大致相同。

    注意使用shmat链接到段,使用shmdt脱离段,使用shmctl删除段。

    文中给出了两个特殊实例:

    将/dev/zero映射用mmap映射,并指定flag为MAP_SHARED,那么多个进程可以共享此文件映射存储区。好处是无须存在一个实际文件(如果仅仅是为了使用共享存储),而且比较简单,但是只能在相关进程中起作用;除此之外,匿名存储映射也可以完成类似的功能(更加简单)。

  • 相关阅读:
    AIX 常用命令
    local_listener 与 remote_listener 参数说明
    IBM AIX 5.3 系统管理 系统启动过程详解
    exp/imp 与 expdp/impdp 对比 及使用中的一些优化事项
    local_listener 与 remote_listener 参数说明
    SSH 连接慢 与 反向解析
    Configuring raw devices (multipath) for Oracle Clusterware 10g Release 2 (10.2.0) on RHEL5OEL5 [ID 564580.1]
    Parameter DIRECT: Conventional Path Export Versus Direct Path Export [ID 155477.1]
    AIX 系统介绍
    Oracle 数据文件(Datafile ) 大小 限制 说明
  • 原文地址:https://www.cnblogs.com/livewithnorest/p/2914459.html
Copyright © 2011-2022 走看看