深刻理解Linux进程间通信.doc

深刻理解 Linux 进程间通信(IPC)级别 初级 郑彦兴 国防科大计算机学院 2002 年 12 月 11 日 一个大型的应用系统,往往需要众多进程协作,进程(Linux 进程概念见附 1) 间通信的重要性显而易见。 本系列文章阐述了 Linux 环境下的几种主要进程间通 信手段,并针对每个通信手段关键技术环节给出详细实例。为达到阐明问题的目 的,本文还对某些通信手段的内部实现机制进行了分析。 序序 linux 下的进程通信手段基本上是从 Unix 平台上的进程通信手段继承而来的。而 对 Unix 发展做出重大贡献的两大主力 AT 参数 int fd2为一个长度为 2 的文件描述符数组,fd0是读出端,fd1是写入端,函数 的返回值为 0 表示成功,-1 表示失败。当函数成功返回,则自动维护了一个从 fd1到 fd0 的数据通道。 下面实例演示了如何使用 pipe 函数创建管道以及关闭管道。程序中先使用函数 pipe 建 立管道,并使用管道传输数据,在程序的结束部分,释放掉管道占用的文件资源(两个文件 描述符),具体实现如下。 1)在)在 vi 编辑器中编辑以下程序编辑器中编辑以下程序 程序清单 14-1 opro_pipe.c 管道的打开以及关闭操作 include include include int main void int fd2; /* 管道的文件描述符数组 */ char str256; if pipefd include include include define BUFES PIPE_BUF /* PIPE_BUF 管道默认一次性读写的数据 长度*/ int main void int fd2; char bufBUFSZ; pid_t pid; int len; if pipefd 0 close fd0 ; /*父进程中关闭管道的读出端*/ write fd1, “hello my sonn“, 14 ; /*父进程向管道写入 数据*/ exit 0; else close fd1 ; /*子进程关闭管道的写入端*/ len read fd0, buf, BUFS ; /*子进程从管道中读出数据*/ if len include include include include define BUFES PIPE_BUF void err_quitchar * msg perror msg ; exit1; int main void int fd2; char bufBUFSZ; /* 缓冲区 */ pid_t pid; int len; if pipefd 0 /*父进程中*/ close fd0 ; close fd1 ; exit 0 ; else /*子进程中*/ close fd1 ; /*关闭不使用的文件描述符*/ len read fd0, buf, BUFS ; /*读取消息*/ writeSTDOUT_FILENO, buf, len; exit0; (2)在 shell 中编译该程序如下 gcc bro_bro.c-o bro_bro (3)在 shell 中运行该程序如下 ./ bro_bro hello brother 上述程序中父进程分别建立了 2 个子进程, 在子进程 1 中关闭了管道的读出端, 在子进 程 2 中关闭了管道的输入端,并在父进程中关闭了管道的两端。 注意 程序中父进程在创建第 1 个子进程时并没有关闭管道两端, 而是在创建第 2 个进 程时才关闭管道。这是为了在创建第 2 个进程时,子进程可以继承存活的管道,而不是一个 两端已经关闭的管道。 14.2.4 创建管道的标准库函数创建管道的标准库函数 从程序 14-2 和程序 14-3 中可以总结出管道操作的一个流程。 父进程中先使用 pipe 函数 创建管道,在调用 fork 函数创建子进程,在父子进程中维护管道的数据流向。程序退出时 及时关闭管道的两端,具体流程如图 14-4 所示。 (点击查看大图)图 14-4 匿名管道的创建流程 管道操作的基本流程为先创建一个管道,使用 fork 创建子进程, 在父子进程中关闭不需 要的文件描述符使用管道通信, 程序结束。 由于这是一个比较规范也是比较常用的管道使用 模式,所以在 ANSI/ISO C 中将以上操作定义在两个标准的库函数 popen 和 pclose 中,它们 的函数原型是 include FILE *popen const char * command, const char *mode ; int pclose FILE *stream ; 函数 popen 的参数 command 是一个在 shell 中可运行的命令字符串的指针, 参数 mode 是一个字符指针,这个参数只有两种值可以使用,r 或者 w,分别表示 popen 函数的返回值 是一个读打开文件指针,还是写打开文件指针。当函数失败时返回值为 NULL,并设置出错 变量 errno。 popen 函数先执行创建一个管道,然后调用 fork 函数创建子进程,紧接着执行一个 c 函数调用, 调用/bin/sh -c 来执行参数 command 中的命令字符串, 然后函数返回一个标准的 I/O 文件指针。返回的文件指针类型与参数 mode 有关,如果参数 mode 是 r 则文件指针连接 到 command 命令的标准输出,如果是 w 则文件指针连接到 command 命令的标准输 入。 为了关闭 popen 函数返回的文件指针, 可以调用 pclose 函数。 pclose 函数的参数 stream 是一 个 popen 打开的文件描述符,当函数失败返回-1。 下面实例演示了使用 popen 和 pclose 函数实现调用 shell 命令 cat 来打印一个文件到显 示器的程序。 程序中先使用 popen 函数为 cat 命令创建一条数据管道, 并指定数据管道从 cat 命令的输出读出数据。在后续的代码中使用 fgets 函数读出数据,并将数据显示到标准输出 中。 1)在)在 vi 编辑器中编辑该程序如下编辑器中编辑该程序如下 程序清单 14-4 recat.c 使用 popen 和 pclose 函数创建管道 include include include include include define BUFES PIPE_BUF int main void FILE *fp; char * “cat file1“; /*shell 命令*/ char * bufBUFSZ; if fp popen , “r“NULL /*创建子进程到父进 程的数据管道*/ perror “ failed to popen “ ; exit 1 ; while fgetsbuf, BUFSZ, fp NULL /*读出管道的数据 */ printf “s“, buf ; pclose fp ; /*关闭管道*/ exit 0 ; (2)在 shell 中编译该程序如下 gcc recat.c-o recat (3)在 shell 中运行该程序如下 ./ recat Used the popen and pclose function to create a pipe 说明 在程序 14-4 recat.c 中, 使用 popen 和 pclose 函数创建管道并关闭管道, 使用 gets 函数从管道输出端读取数据并打印到标准输出中,使用 popen 和 pclose 可以更简洁地控制 管道,而无需那些繁杂的代码。当然这样做的结果是降低了程序员对管道的控制能力。 例如,popen 函数返回的是文件指针,所以,在管道读写时就不能使用低级的 read 和 write I/O 调用了, 只能使用基于文件指针的 I/O 函数, 并且在 popen 函数中调用 c 函数来 复写子进程,这也是要花费一段运行时间的。 14.3 FIFO 管道管道 FIFO 也称为有名管道,它是一种文件类型,在文件系统中可以看到。程序中可以查看 文件 stat 结构中 st_mode 成员的值来判断文件是否是 FIFO 文件。创建一个 FIFO 文件类似 于创建文件,FIFO 文件就像普通文件一样。本小节将介绍 FIFO 管道。 14.3.1 FIFO 的概念的概念 在本章 14.2.2 小节详细说明了匿名管道的缺点以及限制条件,在 FIFO 中可以很好地解 决在无关进程间数据交换的要求, 并且由于它们是存在于文件系统中的, 这也提供了一种比 匿名管道更持久稳定的通信办法。 FIFO 的通信方式类似于在进程中使用文件来传输数据,只不过 FIFO 类型文件同时具 有管道的特性。在数据读出时,FIFO 管道中同时清除数据。在 shell 中 mkfifo 命令可以建立 有名管道,下面通过一个实例来帮助读者理解 FIFO。mkfifo 命令的帮助手册如下所示 mkfifo option name. 其中 option 选项中可以选择要创建 FIFO 的模式, 使用形式为-m mode, 这里 mode 指出将要 创建 FIFO 的八进制模式,注意,这里新创建的 FIFO 会像普通文件一样受到创建进程的 umask 修正。在 shell 中输入命令如下 mkfifo -m 600 fifocat cat fifocat ./recat fifocat include include include include include define BUFES PIPE_BUF int main void FILE *fp; char * “cat file1“; /*shell 命令*/ char * bufBUFSZ; . . . pclose fp ; /*关闭管道*/ exit 0 ; _ 以上实例使用系统命令 mkfifo 创建 FIFO 类型文件 fifocat,并通过 14.2.4 节的程序 recat 来 读取文件 recat.c, 将程序的标准输出从定向到 fifocat 中, 再使用命令 cat 从 fifocat 读出数据。 14.3.2 创建创建 FIFO 创建一个 FIFO 文件类似于创建文件,FIFO 文件就像普通文件一样,也是可以经过路 径名来访问的。相应文件 stat 结构的域 st_mode 的编码指明了文件是否是 FIFO 类型。FIFO 管道通过函数 mkfifo 创建,函数原型如下 include include int mkfifo const char * filename, mode_t mode ; mkfifo 函数中参数 mode 指定 FIFO 的读写权限,新创建 FIFO 的用户 ID 和组 ID 规则 域open函数相同。 参数filename指定新创建FIFO的文件名称。 函数如果成功返回0, 出 错 返回-1,并更改 errno 的值。errno 有可能出现的值为EACCESS、EEXIST、ENAMETOO- LONG、ENOENT、ENOSPE、ENOTDIR 和 EROFS。 下面实例演示了如何使用 mkfifo 函数来创建一个 FIFO。程序中从程序的命令行参数中 得到一个文件名,然后使用 mkfifo 函数创建 FIFO 文件。新创建的 FIFO 只具有读写权限。 由于 FIFO 文件的特性,所以它被隐性地规定不具有执行权限。 1)在)在 vi 编辑器中编辑该程序如下编辑器中编辑该程序如下 程序清单 14-5 create_fifo.c 使用 mkfifo 函数创建 FIFO 管道 include include include include include int main int argc, char *argv mode_t mode 0666; /*新创建的 FIFO 模式*/ if argc 2 /*向用户提示程序使用帮助*/ printf“USEMSG create_fifo fifonamen“; exit 1; /* 使用 mkfifo 函数创建一个 FIFO 管道*/ if mkfifo argv1, mode include include include include include include include define BUFES PIPE_BUF int mainvoid int fd ; int n, i ; char bufBUFES; time_t tp; printf“I am dn“,getpid; /*说明进程的 ID*/ iffdopen“fifo1“,O_WRONLY include include include include include include include define BUFES PIPE_BUF int mainvoid int fd; int len; char bufBUFES; mode_t mode 0666; /* FIFO 文件的权限 */ iffdopen“fifo1“,O_RDONLY0 /* 开始进行通信 */ printf“read_fifo read s“,buf; closefd; /* 关闭 FIFO 文件 */ exit0; 程序中使用 open 函数以读方式打开一个名为 fifo1 的 FIFO 管道,并循环读出管道的数 据,这里使用 while 循环的作用就是确保数据可以全部读出,因为在读 FIFO 管道数据时, 默认的是一次性读取 PIPE_BUF 个字节, 当管道中数据多于 PIPE_BUF 个字节时, 一次性读 出 PIPE_BUF-1 个字节,然后 read 函数返回,再打印数据到标准输出。 (2)在 shell 中分别编译上述两个程序如下 gcc write_fifo.c-o write_fifo gcc read_fifo.c-o read_fifo (3)在 shell 中使用 mkfifo 创建程序中将要用到的 FIFO 管道。 mkfifo -m 666 fifo1 (4)打开两个 shell 分别运行程序 write_fifo 和程序 read_fifo。一个 shell 中输入如下 ./write_fifo i am 3708 Send msgwrite_fifo 3708 sends Thu Apr 17 182601 2008 Send msgwrite_fifo 3708 sends Thu Apr 17 182604 2008 Send msgwrite_fifo 3708 sends Thu Apr 17 182607 2008 Send msgwrite_fifo 3708 sends Thu Apr 17 182610 2008 Send msgwrite_fifo 3708 sends Thu Apr 17 182613 2008 Send msgwrite_fifo 3708 sends Thu Apr 17 182616 2008 Send msgwrite_fifo 3708 sends Thu Apr 17 182619 2008 Send msgwrite_fifo 3708 sends Thu Apr 17 182622 2008 Send msgwrite_fifo 3708 sends Thu Apr 17 182625 2008 Send msgwrite_fifo 3708 sends Thu Apr 17 182628 2008 另一个 shell 中输入如下 ./read_fifo read_fifo read write_fifo 3708 sends Thu Apr 17 182601 2008 read_fifo read write_fifo 3708 sends Thu Apr 17 182604 2008 read_fifo read write_fifo 3708 sends Thu Apr 17 182607 2008 read_fifo read write_fifo 3708 sends Thu Apr 17 182610 2008 read_fifo read write_fifo 3708 sends Thu Apr 17 182613 2008 read_fifo read write_fifo 3708 sends Thu Apr 17 182616 2008 read_fifo read write_fifo 3708 sends Thu Apr 17 182619 2008 read_fifo read write_fifo 3708 sends Thu Apr 17 182622 2008 read_fifo read write_fifo 3708 sends Thu Apr 17 182625 2008 read_fifo read write_fifo 3708 sends Thu Apr 17 182628 2008 上述例子可以扩展成客户端与服务器通信的实例,write_fifo 的作用类似于客户端,可以打 开多个客户端向一个服务器发送请求信息,read_fifo 类似于服务器,它适时监控着 FIFO 的 读出端,当有数据时,读出并进行处理,但是有一个关键的问题是,每一个客户端必须预先 知道服务器提供的 FIFO 接口,如图 14-5 所示。 图 14-5 FIFO 在客户端与服务器通信的应用 1 14.3.4 FIFO 的缺点的缺点 当然 FIFO 也有它的局限性,如图 14-6 所示。客户端可以发请求到服务器,但前提是要 知道一个公共的 FIFO 通道,对于实现服务器回传应答到客户端的问题,可以通过为每一个 客户端创建一个专用的 FIFO,来实现回传应答。但也有不足,服务器会同时应答成千上万 个客户端,创建如此多的 FIFO 是否会使系统负载过大,相应的如何判断客户端是否因意外 而崩溃成为难题,或者客户端不读取应答直接退出,所以服务器必须处理 SIGPIPE 信号, 并做相应处理。 说明在服务器端打开公共 FIFO 的时候,如果仅以读打开,则当所有的客户端都退出 时,服务器端会读取到文件结束符。这个问题的解决办法是服务器以读写打开公共 FIFO, 如图 14-6 所示。服务器与客户端如何实现互相通信。 图 14-6 FIFO 在客户端与服务器通信的应用 2 14.4 System V IPC/POSIX IPC System V IPC 包括三种进程通信方式,即消息队列、信号量以及共享存储器,这是一种 比较古老的方式,在最近的版本中已逐渐地被 POSIX IPC 而取代。当然,两者之间还是有 着密切关系的,实现的道理也还是一样。 消息队列、信号量以及共享存储器这三种 IPC 的几种结构有时又称 IPC 对象,它不同 于前面提到的管道和 FIFO。管道和 FIFO 是基于文件系统的,例如,可在文件系统中看到 某一个 FIFO 类型文件, 而 System V IPC 是基于系统内核的, 可以使用命令 ipcs 来查看系统 当前的 IPC 对象的状态,本节将详细介绍它们各自的特点以及使用实例。 14.4.1 IPC 对象的概念对象的概念 由于消息队列、信号量以及共享存储器三种 IPC 有很多相类似的特性,所以本节将对 它们的特性,以及相关知识做一些详细的介绍,IPC 对象示意图如图 14-7 所示。 (点击查看大图)图 14-7 IPC 对象的应用示意图 如图 14-7 所示,IPC 对象是活动在内核级别的一种进程间通信的工具。存在的 IPC 对 象通过它的标识符来引用和访问,这个标识符是一个非负整数,它唯一的标识了一个 IPC 对象,这个 IPC 对象可以是消息队列或信号量或共享存储器中的任意一种类型。 在 Linux 系统中标识符被声明成整数,所以可能存在的最大标识符为 65535。这里标识 符与文件描述符有所不同,使用 open 函数打开一个文件时,返回的文件描述符的值为当前 进程最小可用的文件描述符数组的下标。 IPC 对象删除或创建时相应的标识符的值会不断增 加到最大的值,归零循环分配使用。 IPC 的标识符只解决了内部访问一个 IPC 对象的问题, 如何让多个进程都访问某一个特 定的 IPC 对象还需要一个外部键(key),每一个 IPC 对象都与一个键相关联。这样就解决 了多进程在一个 IPC 对象上汇合的问题。 创建一个 IPC 对象时需要指定一个键值,类型为 key_t,在中定义为一个 长整型。键值到标识符的转换是由系统内核来维护的。当有了一个 IPC 对象的键值,如何 让多个进程知道这个键,可以有多种实现的办法。 可以使用文件来做中间的通道, 创建 IPC 对象进程, 使用键 IPC_PRIVATE 成功建立 IPC 对象之后,将返回的标识符存储在一个文件中。其他进程通过读取这个标识符来引用 IPC 对象通信。 定义一个多个进程都认可的键,每个进程使用这个键来引用 IPC 对象,值得注意的是, 创建 IPC 对象的进程中,创建 IPC 对象时如果该键值已经与一个 IPC 对象结合,则应该删 除该 IPC 对象,再创建一个新的 IPC 对象。 多进程通信中,对于指定键引用一个 IPC 对象而言,可能不具有拓展性,并且在该键 值已经被一个 IPC 对象结合的情况下。所以必须删除这个存在对象之后再建立一个新的。 这有可能影响到其他正在使用这个对象的进程。函数 ftok 可以在一定程度上解决这个问题, 函数 ftok 可以使用两个参数生成一个键值,函数原型如下 include key_t ftok const char *path, int id ; 函数中参数 path 是一个文件名。函数中进行的操作是,取该文件的 stat 结构的 st_dev 成员和 st_ino 成员的部分值,然后与参数 ID 的第八位结合起来生成一个键值。由于只是使 用 st_dew 和 st_ino 的部分值,所以会丢失信息,不排除两个不同文件使用同一个 ID,得到 同样键值的情况。 系统为每一个 IPC 对象保存一个 ipc_perm 结构体,该结构说明了 IPC 对象的权限和所 有者,每一个版本的内核各有不用的 ipc_perm 结构成员。若要查看详细的定义请参阅文件 。 struct ipc_perm key_t key; uid_t uid; gid_t gid; uid_t cuid; gid_t cgid; unsigned short mode; unsigned short seq; ; 每一种版本的 ipc_perm 结构体定义至少要包含上述几个域。当调用 IPC 对象的创建函 数(semget msgget shmget )时,会对 ipc_perm 结构的每一个域赋值。在后续的操作中如需 修改这几个域则调用相应的控制函数(msgctl semctl shmctl)。 注意只有超级用户或者创建 IPC 对象的进程有权改变 ipc_perm 结构的值。结构中的 mode 域类似于文件的 stat 结构的 mode 域,但是不可以有执行权限。mode 值描述如表 14-3 所示。表 14-3 ipc_perm 的 mode 详解表 操 作者 读 写(更改 更 新) 操 作者 读 写(更改 更 新) 用 户 0400 0200 其 他 0004 0002 组 0040 0020 14.4.2 IPC 对象的问题对象的问题 IPC 对象所存在的问题主要集中在以下几点 过于繁杂的编程接口,比起使用其他通信方式,IPC 所要求的代码量要明显增多。 IPC 不使用通用的文件系统,这也是饱受指责的原因。所以不能使用标准 I/O 操作函数 来读写 IPC 对象。为此不得不新增加一些函数来支持必要的一些操作(例如 msgget msgrev msgctl 等) 并且对于不同类型的 IPC 对象都有一系列特定的操作函数。 由于 IPC 不使用文件 描述符,所以不能使用多路 I/O 监控函数 select 及 poll 函数来操作 IPC 对象。 缺少的资源回收机制。由于 IPC 对象在使用过程中并不保存引用计数,所以当出现一 个进程创建了 IPC 对象然后退出时,则这个对象只有在出现后面几种情况才会被释放或者 删除,即由某一个进程读出消息,或者 IPC 的所有者或超级用户删除了这个对象。这也是 IPC 相对于管道或 FIFO 所欠缺的资源回收机制。 14.4.3 IPC 对象系统命令对象系统命令 在 shell下可以使用一些命令来操作 IPC 对象, 下面通过几个实际的例子来帮助理解 IPC 对象,使用 ipcs 可以显示 IPC 的状态。在 shell 中输入 ipcs -a Shared Memory Segments key shmid owner perms bytes nattch status 0 x00000000 65536 root 600 393216 2 dest 0 x00000000 2654209 root 666 4096 0 0 x00000000 2752516 root 666 4096 0 Semaphore Arrays key semid owner perms nsems 0 x00000000 294911 root 666 1 Message Queues key msqid owner perms used-bytes messages 注意 ipcs 输出的信息中的 key 以及 shmid,key 标识的是 IPC 对象的外键,shmid 标识 的 IPC 对象的标识符。owner 标识的是 IPC 所属的用户,perms 标识权限。可以使用 ipcrm 命令来删除一个 IPC 对象,使用实例如下。在 shell 中输入 ipcrm -m 2752516 ipcs -a Shared Memory Segments key shmid owner perms bytes nattch status 0 x00000000 65536 root 600 393216 2 dest 0 x00000000 2654209 root 666 4096 0 Semaphore Arrays key semid owner perms nsems 0 x00000000 294911 root 666 1 Message Queues key msqid owner perms used-bytes messages 在应用中,如果使用 kill 命令删除程序后,发现系统资源例如内存的使用量仍然很高, 则应检查系统 IPC 状态,并使用 ipcrm 命令删除不使用的 IPC。 14.5 共享内存共享内存 共享内存从字面意义解释就是多个进程可以把一段内存映射到自己的进程空间, 以此来 实现数据的共享以及传输, 这也是所有进程间通信方式中最快的一种。 共享内存是存在于内 核级别的一种资源,在 shell 中可以使用 ipcs 命令来查看当前系统 IPC 中的状态,在文件系 统中/proc 目录下有对其描述的相应文件。 14.5.1 共享内存的概念共享内存的概念 在系统内核为一个进程分配内存地址时, 通过分页机制可以让一个进程的物理地址不连 续, 同时也可以让一段内存同时分配给不同的进程。 共享内存机制就是通过该原理来实现的, 共享内存机制只是提供数据的传送, 如何控制服务器端和客户端的读写操作互斥, 这就需要 一些其他的辅助工具,例如,记录锁概念,如图 14-8 所示,描述了多进程如何使用共享内 存通信。 如图 14-8 所示。箭头方向描述了进程地址空间映射到系统内存地址的位置。对于每一 个共享存储段,内核会为其维护一个 shmid_ds 类型的结构体(shmid_ds 结构体定义在头文 件中)。shmid_ds 结构体定义如下 (点击查看大图)图 14-8 共享内存示意图 struct shmid_ds struct ipc_perm shm_perm; / size_t shm_segsz; pid_t shm_lpid; pid_t shm_cpid; shmatt_t shm_nattch; time_t shm_atime; time_t shm_dtime; time_t shm_ctime; ; 结构体 shmid_ds 会根据不同的系统内核版本而略有不同,并且在不同的系统中会对共享存 储段的大小有限制,在应用时请查询相应的系统手册。 14.5.2 共享内存的创建共享内存的创建 共享内存是存在于内核级别的一种资源,在 shell 中可以使用 ipcs 命令来查看当前系统 IPC 中的状态,在文件系统/proc 目录下有对其描述的相应文件。函数 shmget 可以创建或打 开一块共享内存区。函数原型如下 include int shmget key_t key, size_t size, int flag ; 函数中参数 key 用来变换成一个标识符,而且每一个 IPC 对象与一个 key 相对应。当新 建一个共享内存段时,size 参数为要请求的内存长度(以字节为单位)。 注意内核是以页为单位分配内存,当 size 参数的值不是系统内存页长的整数倍时, 系统会分配给进程最小的可以满足 size 长的页数,但是最后一页的剩余部分内存是不可用 的。 当打开一个内存段时,参数 size 的值为 0。参数 flag 中的相应权限位初始化 ipc_perm 结构体中的 mode 域。同时参数 flag 是函数行为参数,它指定一些当函数遇到阻塞或其他情 况时应做出的反应。shmid_ds 结构初始化如表 14-4 所示。 表 14-4 shmid_ds 的初始化 shmid_ds结构 数据 初 值 shmid_ds结构 数据 初 值 shm_lpid 0 shm_dtime 0 shm_nattach 0 shm_ctime 系统当前值 shm_atime 0 shm_segsz 参数 size 下面实例演示了使用 shmget 函数创建一块共享内存。 程序中在调用 shmget 函数时指定 key 参数值为 IPC_PRIVATE,这个参数的意义是创建一个新的共享内存区,当创建成功后 使用 shell 命令 ipcs 来显示目前系统下共享内存的状态。 命令参数-m 为只显示共享内存的状 态。 (1)在 vi 编辑器中编辑该程序如下 程序清单 14-8 create_shm.c 使用 shmget 函数创建共享内存 include include include include include define BUFSZ 4096 int main void int shm_id; /*共享内存标识符*/ shm_idshmgetIPC_PRIVATE, BUFSZ, 0666 ; if shm_id int shmctl int shm_id, int , struct shmid_ds *buf ; 函数中参数 sh_mid 为所要操作的共享内存段的标识符,struct shmid_ds 型指针参数 buf 的作用与参数 的值相关,参数 指明了所要进行的操作,其解释如表 14-5 所示。 表 14-5 shmctl 函数中参数 详解 的值 意 义 IPC_STAT 取shm_id所指向内存共享段的shmid_ds 结构,对参数buf指向的结构赋值 IPC_SET 使用buf指向的结构对sh_mid段的相关结 构赋值,只对以下几个域有作用,shm_perm. uid shm_perm.gid以及shm_perm.mode 注意此命令只有具备以下条件的进程才可以请求 1进程的用户ID等于shm_perm.cuid或者 等于shm_perm.uid 2超级用户特权进程 IPC_RMID 删除shm_id所指向的共享内存段,只有当 shmid_ds结构的shm_nattch域为零时,才 会真正执行删除命令,否则不会删除该段 注意此命令的请求规则与IPC_SET命令相同 SHM_LOCK 锁定共享内存段在内存,此命令只能由超级用户请 求 SHM_UNLO CK 对共享内存段解锁,此命令只能由超级用户请求 使用函数 shmat 将一个存在的共享内存段连接到本进程空间,其函数原型如下 include void *shmat int shm_id, const void *addr, int flag ; 函数中参数 shm_id 指定要引入的共享内存, 参数 addr 与 flag 组合说明要引入的地址值, 通常只有 2 种用法,addr 为 0,表明让内核来决定第 1 个可以引入的位置。addr 非零,并且 flag 中指定 SHM_RND,则此段引入到 addr 所指向的位置(此操作不推荐使用,因为不会 只对一种硬件上运行应用程序,为了程序的通用性推荐使用第 1 种方法),在 flag 参数中 可以指定要引入的方式(读写方式指定)。 说明函数成功执行返回值为实际引入的地址,失败返回-1。shmat 函数成功执行会将 shm_id 段的 shmid_ds 结构的 shm_nattch 计数器的值加 1。 当对共享内存段操作结束时, 应调用 shmdt 函数,作用是将指定的共享内存段从当前进 程空间中脱离出去。函数原型如下 include int shmdt void *addr; 参数addr是调用shmat函数的返回值, 函数执行成功返回0, 并将该共享内存的shmid_ds 结构的 shm_nattch 计数器减 1,失败返回-1。 下面实例演示了操作共享内存段的流程。 程序的开始部

深刻理解linux进程间通信 pdf,深刻理解Linux进程间通信.doc相关推荐

  1. linux 解析pdf下载工具,Linux高级系统级性能分析工具-perf.pdf

    Linux高级系统级性能分析工具-perf Linux 的系统级性能剖析工具‐perf (二) 承刚 TAOBAO  Kernel Team chenggang.qin@ 第三章  Perf top ...

  2. linux 网络管理 pdf,Windows与Linux网络管理与维护 PDF扫描版[194MB]

    高等职业教育"十二五"规划教材:windows与linux网络管理与维护是一本基于工作过程的工学结合教材,依据中小企业系统管理员/网络管理员岗位的典型工作任务,设计了7个学习情境. ...

  3. 如何在linux部署pdf文档,LINUX安装部署文档.pdf

    LINUX 安装部署详解文档 文档内容简介: 一:详解安装前的准备工作---------------------- 二:安装LINUX ---------------------------... 三 ...

  4. linux退出pdf阅读,Ubuntu/Linux 下pdf阅读器Zathura(类vim操作)

    框架 Onboard-引导页样式制作库 设置背景图片或者背景movie,然后在它们之上生成数个ViewController,默认是顶部一张图片,下面是标题和详细介绍,最下面是按钮和pagegithub ...

  5. Linux——Linux概念架构的理解

    摘要 Linux kernel成功的两个原因:(1)灵活的架构设计使得大量的志愿开发者能够很容易加入到开发过程中:(2)每个子系统(尤其是那些需要改进的)都具备良好的可扩展性.正是这两个原因使得Lin ...

  6. 【译】Linux概念架构的理解

    声明:本文翻译自Conceptual Architecture of the Linux Kernel 摘要 Linux kernel成功的两个原因:(1)灵活的架构设计使得大量的志愿开发者能够很容易 ...

  7. Linux概念架构的理解

    摘要 Linux kernel成功的两个原因:(1)架构设计支持大量的志愿开发者加入到开发过程中:(2)每个子系统,尤其是那些需要改进的,都支持很好的扩展性.正是这两个原因使得Linux kernel ...

  8. 理解JVM如何使用Windows和Linux上的本机内存

    转至:http://www.chineselinuxuniversity.net/articles/23291.shtml 摘要:Java™ 堆耗尽并不是造成 java.lang.OutOfMemor ...

  9. 深入理解linux文件系统( 理解inode与block,理解硬链接软链接,掌握恢复误删文件及其分析方法,掌握用户日志及其查询命令 )

    文章目录 深入理解linux文件系统 前言 inode与block详解 inode和bolck概述 1:数据(block)块: 2:元信息 : inode(索引节点) inodu的内容 Linux系统 ...

最新文章

  1. 如果我睡着了请不要叫醒我
  2. [转载] Linux里面的文件目录类指令
  3. echarts tooltip被遮挡_echarts 的tooltip定位到当前图,避免溢出和遮挡
  4. i/o timeout , 希望你不要踩到这个net/http包的坑
  5. android 开发50个技巧面向切面编程思想
  6. Proxmark3教程1:小白如何用PM3破解复制M1全加密门禁IC卡
  7. Centos安装(更新)git(亲测有效)
  8. Shell自动备份部署新项目
  9. 【知识图谱系列】多关系异质知识图谱表示学习综述
  10. Linux 系统实现 SSH 连接的 3 种 方式
  11. Unity Webgl生成带图片、表格的文本(DOC、PDF)
  12. delphi xe 10 程式外观
  13. python编程星期几_python如何获取星期几
  14. App中使用微信公众号的模版消息来进行消息推送
  15. 用双轨驶向未来:千兆宽带将如何改变我们的家庭生活?
  16. EPP (Enhanced Parallel Port 增强型并口)
  17. Response响应详解
  18. feishu-飞书api
  19. 字体转换 (代码整理 备忘)
  20. m4s格式转换mp3_超级详细!如何将B站缓存m4s文件无损转换为mp4格式

热门文章

  1. DM数据库的体系结构
  2. python语言程序设计有用吗,python对设计师有什么用
  3. Oracle 物化视图(MV)详解
  4. C#为什么 Dictionary 没有 AddRange 方法?
  5. AutoDetectChangesEnabled及AddRange解决EF插入的性能问题
  6. 仙境传说 第一章之二 卢渊*冰雷魔法师
  7. 室内风水植物摆放的10个要素
  8. mysql添加外键1215错误_MySQL添加外键时报错:1215 Cannot add the foreign key constraint的解决方法...
  9. “穷人” 就不应该创业?
  10. 简单PageRank —— 希拉里邮件门