《APUE》学习记录之———进程间通信

进程间通信:

    管道:

    管道只能在具有公共祖先的两个进程之间使用,通常,一个管道由一个进程创建,在进程调用fork之后,这个管道就可以在父子进程之间使用;

#include
int pipe(int fd[2]);

    fd[0]为读打开,fd[1]为写打开,fd[1]的输出是fd[0]的输入(创建一个管道,然后调用fork,父进程关闭其读端,子进程关闭其写端,就建立了父进程写子进程读的管道);

    函数popen和pclose

#include
FILE * popen(const char *cmdstring, const char *type);    // 成功返回文件指针,错误返回NULL
int pclose(FILE *fp);                                     // 成功返回cmdstring的终止状态,错误,返回-1

    函数popen先执行fork,然后调用exec执行cmdstring,并且返回一个标准的I/O文件指针,type如果是“r”,则文件指针链接到cmdstring的标准输出,如果type是“w”,则文件则连接到cmdstring的标准输入;

    协同进程

    UNIX系统过滤程序从标准输入读取数据,向标准输出写数据,几个过滤程序通常在shell管道中线性连接,当一个过滤程序既产生某个过滤程序的输出,有读取带过滤程序的输入时,它就变为协同进程;

    popen只提供连接到另外一个进程的标准输入或标准输出的单向管道,而协同进程则有连接到另外一个进程的两个单向管道:一个接到其标准输入,另外一个接到其标准输出(可以将数据写到标准输入,处理后,从标准输出读取数据);

int fd1[2],fd2[2];
if((pid = fork()) > 0){    // parent
    close(fd1[0]);
    close(fd2[1]);
    ...
}else{                     // child 
    close(fd1[1]);
    close(fd2[0]);
    ...
}

    FIFO

    FIFO被称为命名管道( popen,协同进程其实都是匿名管道的一种),未命名的管道只能在两个相关的进程之间使用,而且这两个相关进程还必须有一个共同创建它们的祖先进程,FIFO可以用于不相关进程交换数据;

#include
int mkfifo(const char* *path, mode_t mode);                    //成功返回0,失败返回-1
int mkfifioat(int fd, const char *path, mode_t mode);          //成功返回0,失败返回-1

    path实际上相当于管道的“名字”,所以一个给定的FIFO会有多个写进程是常见的,这就意味着如果不希望多个进程所写的数据交叉,则必须考虑原子写操作;

    FIFO常用的两种用途:

    1.shell命令将FIFO将数据从一条管道传到另外几条管道时,不需要创建中间临时文件;(单写入多读取,发散

    2.客户进程-服务器进程中,FIFO用作汇聚点,在客户进程和服务器进程之间传递数据;(多写入单读取,汇聚

    消息队列

    消息队列是消息的链接表,存储在内核中,由消息队列标识符标识;

#include
int msgget(key_t key, int flag);                // 成功,返回队列ID,错误,返回-1
int msgsnd(int msqid, const void *ptr, siez_t nbytes, int flag); // 成功,返回0,错误,返回-1
ssize_t msgrcv(int msqid, void* ptr, size_t nbytes, long type, int flag); // 成功,返回消息数据部分的长度,错误返回-1

    msgget用于创建一个新队列,或打开一个现有队列,msgsed将心消息添加到队列尾端,msgrcv用于从队列中读取消息,并不一定以先进先出次序读取消息,也可以按消息的类型字段读取消息;

    信息量

    信号量是一个计数器(与管道,FIFO,和消息队列不同),用于多个进程(线程)提供对共享数据的访问;

    为了获得共享资源,进程需要执行以下的动作:

    1. 测试控制资源的信号量;

    2. 若为正,则进程可以使用该资源,这种情况下,进程会将信号量减一(资源被占用);

    3. 否则,信息量的值为0,进程进入休眠状态,直到信号量大于0,进程被唤醒,进入第一步;

    共享存储

    共享存储允许两个或多个进程共享一个给定的存储区,因为数据无需在客户进程和服务器进程之间复制,所有这是最快的一种IPC(进程间通信);
    因为共享空间可能会出现竞争环境,所有,对空间的读写应该加锁(或设置信号量);

    共享存储的一种形式上,在多个进程中将同一个文件映射到它们的地址空间,XSI共享则是没有相关的文件,XSI共享存储的是内存的匿名段;

    杂项:

    IPC(信号量,共享存储,消息队列)的问题是:
    IPC 结构是在系统范围内起作用的,没有引用计数,如果进程创建了一个消息队列,并且在队列中放入了消息,然后终止,那么消息队列及其内容不会被删除,而与管道相比,当最后一个引用管道的进程终止时,管道就被完全地删除了,最后一个引用FIFO的进程终止时,虽然FIFO的名字仍保留在系统,但是留在FIFO的数据已经被删除;

    IPC结构不使用文件描述符,所以不能对它们使用多路转接I/O函数(select 和  poll),使得很难一次使用一个以上的IPC结构;

    信息量实际上是同步原语,而不是IPC,常用于共享资源(共享存储)的同步访问;

你可能感兴趣的:(学习笔记)