8.ipc

进程间通信

Linux中的进程间通信主要有:管道FIFO消息队列信号量共享存储以及网络IPC中的套接字

1.管道

管道是最古老的IPC,有以下两种限制:

  • 半双工
  • 只能在具有公共祖先的两个进程间使用

管道通过pipe函数创建:

#include<unistd.h>
int pipe(int fd[2]);
/* 返回值:成功返回0,失败返回-1*/

fd返回两个文件描述符:fd[0]为读打开,fd[1]为写打开。fd[1]的输出是fd[0]的输入。其关系可以用下图描述:

pipe

而对于进程间的pipe关系为:

进程间pipe

对于管道一端被关闭后,下列两条规则适用:

  • 一个写端被关闭的管道时,所有数据都被读取后,read返回0,表示文件结束。
  • 一个读端被关闭的管道,则产生信号SIGPIPE。如果忽略该信号或者捕捉该信号并从其处理程序返回,则write返回-1,errno设置为EPIPE

下面通过实例程序演示,创建一个从父进程到子进程的管道,并且父进程经由该管道向子进程传送数据。

#include "apue.h"

int
main(void)
{
    int     n;
    int     fd[2];
    pid_t   pid;
    char    line[MAXLINE];

    if (pipe(fd) < 0)
        err_sys("pipe error");
    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid > 0) {       /* parent */
        close(fd[0]);
        write(fd[1], "hello world\n", 12);
    } else {                    /* child */
        close(fd[1]);
        n = read(fd[0], line, MAXLINE);
        write(STDOUT_FILENO, line, n);
    }
    exit(0);
}

2.函数popen和pclose

标准I/O库提供了两个函数popenpclose用于实现:创建一个管道,fork一个子进程,关闭未使用的管道端,执行一个shell运行命令,然后等待命令终止。

#include <stdio.h>
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的标准输入。

popenRead

<center>read</center>

popenWrite

<center>write</center>
shell会自动扩展cmdstring的语句,因此popen正常可以如下使用:

fp = popen("ls *.c", "r");

利用这两个函数可以减少代码量。

3.FIFO

FIFO又被称为命名管道,与PIPE不同,FIFO可以用于不相关的进程间通信。创建FIFO的方法与创建文件类似,因为FIFO也是一种文件类型,FIFO的路径名存在于文件系统中。

#include <sys/stat.h>
int mkfifo(const char *path, mode_t mode);
int mkfifoat(int fd, const char *path, mode_t mode);
/* 返回值:成功返回0,失败返回-1 */

mkfifomodeopenmode相同。mkfifoat可以用来在fd文件描述符指定的位置创建FIFO

FIFO可以由多个写进程,通常有以下两种用途:

  • shell命令使用FIFO将数据从一条管道传送到另一条时,无需创建中间临时文件
  • 客户进程-服务器进程应用程序中,FIFO用作汇聚点,在二者之间传递数据。

4.消息队列

消息队列是消息的连接表,存储在内核中,由消息队列标识符标识。msgget用于创建一个新队列或者打开一个现有队列。msgsnd将新消息添加到队列尾端。msgrcv用于从队列中取消息。

每个队列都有一个msgid_ds结构与其关联:

struct msqid_ds {
    struct ipc_perm msg_perm;   /* ipc限制 */
    msgqnum_t   msg_qnum;       /* 队列中消息数 */
    msglen_t    msg_qbytes;     /* 队列最大字节数 */
    pid_t       msg_lsPID;      /* 最后添加消息的pid */
    pid_t       msg_lrpid;      /* 最后取消息的pid */
    time_t      msg_stime;      /* 最后添加消息的时间 */
    time_t      msg_rtime;      /* 最后取消息的时间 */
    time_t      msg_ctime;      /* 最后change的时间 */
    ...
    };

5.信号量

信号量与前面的IPC不同,它是一个计数器,用于为多个进程提供对共享数据对象的访问。

为了获得共享资源,进程需要执行下列操作:

  1. 测试控制该资源的信号量
  2. 若此信号量为正,则进程可以使用该资源,在该情况下,进程将信号量值减一,表示它占用了一个资源单元
  3. 否则,若此信号量为0,则进程进入休眠状态,直到信号量大于0,进程被唤醒,返回至步骤1.

信号量的由一个无名数据结构表示,至少包含下列成员:

struct{
    unsigned short  semval; /* 信号量的值 */
    pid_t           sempid; /* 最后一次操作的pid */
    unsigned short  semncnt;/* 等待信号量大于0的进程数量 */
    unsigned short  semzcnt;/* 等待信号量等于0的进程数量 */
    ...
    };

6.共享存储

共享存储允许两个或多个进程共享一个给定的存储区。因为数据不需要在进程间复制,因此这是最快的IPC。对于共享存储需要注意的就是对多个进程访问存储区的同步。

内核为每个共享存储段维护这一个结构,该结构至少要为每个共享存储段包含以下成员:

struct shmid_ds{
    struct ipc_perm shm_perm;   /* ipc限制 */
    size_t          shm_segsz;  /* 字节数表示的段大小 */
    pid_t           shm_lpid;   /* 最后shmop()的pid */
    pid_t           shm_cpid;   /* creator 的pid */
    shmatt_t        shm_nattch; /* 当前attached的进程数量 */
    time_t          shm_atime;  /* 最后attach的时间 */
    time_t          shm_dtime;  /* 最后dattach的时间 */
    time_t          shm_ctime;  /* 最后改变的时间 */
    ...
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容