它
这里绝对不可能详细描述进程间的通信,也很难自信地说出自己在这部分内容中达到了什么样的理解,所以在本节的开头,我首先向大家推荐这位著名作者的名作:《在 UNIX》中,其中文译本《UNIX 》已经由机械工业出版社出版, 原文精彩,翻译同样地道,如果你确实对 Linux 下的编程有浓厚的兴趣,那就赶紧把这本书放在你的桌子上或电脑旁边。说了这么多,我心中的敬佩之情很难抑制,不过在这一节中,我们将介绍一些最基本、最简单的进程间沟通知识和概念。
首先,进程间通信至少可以通过发送打开的文件来实现,不同的进程通过一个或多个文件传递信息,这实际上在很多应用中都有用到。不过,一般来说,进程间通信(IPC:)并不包括这种看似低级的通信方式。在 Unix 中实现进程间通信的方法有很多,不幸的是,很少有方法可以在所有 Unix 系统之间移植(唯一的一种方法是半双工管道,这也是最原始的通信方式)。Linux 作为一种新兴的操作系统,几乎支持 Unix 中所有常见的进程间通信方式:管道、消息队列、共享内存、信号量、套接字等。让我们在下面逐一介绍它们。
2.3.1 管道
管道是最古老的进程间通信形式,它们包括无名管道(用于父进程和子进程之间的通信)和命名管道(用于在同一台计算机上运行的任意两个进程之间的通信)。
无名管道由 pipe() 函数创建:
#
int pipe(int [2]);
该参数返回两个文件描述符: [0] open for read 和 [1] open for write。[1] 的输出是 [0] 的输入。以下示例演示如何在父进程和子进程之间进行通信。
# 输入 0
# 1
无效 main() {
int [2];
/* 定义子进程编号 */
pid_t pid;
char buf[256];
int ;
/*创建未命名管道*/
管道 ();
/*创建子进程*/
if((pid = fork()) == -1) {
(“fork/n 中的错误”);
退出 (1);
/*执行子流程 */
if(pid == 0) {
(“在(子).../n”);
/*子进程将数据写入父进程并关闭管道的读取端
close([输入]);
write([], “测试数据”, (“测试数据”));
退出 (0);
} else {
/*执行父进程*/
(“在 () .../n”);
/*父进程从流水线读取子进程写入的数据,并关闭流水线的写入端
关闭([]);
= read([输入], buf, (buf));
(“%d 字节的数据来自 %s/n”,
, buf);
在 Linux 上,可以通过两种方式创建命名管道:命令行 mknod 系统调用和函数。以下两种方法都会在当前目录中生成命名管道:
方法 1: (“”,“rw”);
方法 2:mknod p
生成命名流水线后,您可以使用常见的文件 I/O 函数(如 open、close、read、write 等)对其进行操作。下面是一个简单的示例,假设我们创建了一个命名管道。
/* 进程 1:读取命名管道 */
#
#
无效 main() {
文件*;
int 计数 = 1;
char buf[80];
= fopen(“”, “r”);
if ( == NULL) {
(“./n 中的错误”);
退出 (1);
while ((count = fread(buf, 1, 80, )) > 0)
(“ 来自管道: %s/n”, buf);
();
/* 进程 2:写入命名管道 */
#
#
无效 main() {
文件*;
int 计数 = 1;
char buf[80];
= fopen(“”, “w”);
if ( == NULL) {
(“错误管道。”);
退出 (1);
(buf,“这是命名管道 /n 的测试数据”);
(buf, 1, 80, );
();
2.3.2 消息队列
消息队列用于运行在同一台机器上的进程间通信,它类似于流水线,流水线是用来在系统内核中存储消息的队列,以消息链表的形式出现。消息链表中节点的结构是用 msg 声明的。
其实它是一种逐渐过时的通信方式,我们可以用流管或者接口来代替,所以我们就不解释这个方法了,建议读者忽略它。
2.3.3 共享内存
共享内存是在同一台计算机上运行的进程之间通信的最快方式,因为不需要在不同进程之间复制数据。通常,一个进程会创建一个共享内存区域,其余进程会读取和写入内存区域。有两种方法可以获取共享内存:映射 /dev/mem 设备和内存映像文件。 前一种方法不会给系统带来额外的开销,但在现实中并不常用,因为它会控制实际访问的物理内存,这在 Linux 中只能通过限制 Linux 系统可以访问的内存来实现,这当然是不切实际的。一种常见的方法是通过函数系列使用共享内存进行存储。
使用的第一个函数是它获取共享存储标识符。
#
#
#
int (key_t 键、int 大小、int 标志);
此函数类似于熟悉的函数,其中系统根据请求将大小内存分配为共享内存。Linux 内核中的每个 IPC 结构都有一个非负整数标识符,因此在向消息队列发送消息时只需要引用该标识符。 这个标识符是内核从 IPC 结构体的关键字中得到的,也就是上面第一个函数的 key。数据类型 key_t 在头文件 sys/types.h 中定义,它是一个长数据整数。我们将在后面的部分中再次遇到这个关键词。
当共享内存被创建时,其余进程可以调用 shmat() 将其连接到它们自己的地址空间。
无效 *shmat(int shmid, void *addr, int flag);
shmid 是函数返回的共享存储标识符,addr 和 flag 参数决定如何确定连接地址,函数的返回值是进程数据段的实际地址,进程可以对进程进行读写。
使用共享存储进行进程间通信的重点是同步数据访问,并确保当进程读取数据时,它想要的数据已经写入。通常,信号量用于同步对共享内存数据的访问,并且可以通过使用函数设置共享内存的某些标志(如 、 等)来实现。
2.3.4 信号量
信号量,又称信号量,用于协调不同进程之间的数据对象,主要应用是上一节中进程间通信的共享内存方式。从本质上讲,信号量是一个计数器,用于记录对资源(如共享内存)的访问。通常,为了获得共享资源,进程需要执行以下操作:
(1) 测试控制资源的信号量。
(2) 如果此信号量的值为正,则允许使用该资源。 该过程将信号量减去 1。
(3) 如果信号量为 0,则表示资源当前不可用,进程进入休眠状态,直到信号量值大于 0,进程被唤醒并转移到步骤 (1)。
(4) 当进程不再使用信号量控制的资源时,信号量值增加 1。如果进程此时处于等待此信号量的休眠状态,请唤醒该进程。
维护信号量状态的是 Linux 内核操作系统,而不是用户进程。我们可以在头文件 /usr/src/linux//linux/sem.h 中看到内核用来维护信号量状态的各种结构的定义。 信号量是用户可以单独用于集合的每个元素的数据集合。要调用的第一个函数是获取信号量 ID。
SEM {
短 ;/* 最后一个的 PID */
;/*价值*/
;/* num procs in */
;/* 进程数 = 0 */
#
#
#
int (key_t 键, int nsems, int flag);
key 是前面提到的 IPC 结构的关键字,flag 将决定将来是创建新的信号量集还是引用现有的信号量集。nsems 是该集中的信号量数量。如果要创建新集合(通常在服务器中),则必须指定 nsems;如果要引用现有的信号量集合(通常在客户端中),请将 nsems 指定为 0。
函数用于操作信号量。
int (int semid, int , int cmd, union semun arg);
通过 cmd 参数实现不同的操作,头文件 sem.h 中定义了 7 种不同的操作,可以作为实际编程的参考。
semop 函数会自动对信号量集合执行一组操作。
int semop(int semid, [], nops);
是指向信号量操作数组的指针。NOPS 指定该数组中的操作数。
让我们看一个具体的例子,它为特定的 IPC 结构创建一个关键字和一个信号量,为这个信号量编制索引,修改索引指向的信号量的值,最后我们清除这个信号量。在下面的代码中,函数 ftok 生成了我们上面提到的唯一 IPC 关键字。
#
#
#
#
无效 main() {
key_t ; /* 定义 IPC 关键字 */
int id;
;
Union Semun ;
int i;
/* 生成关键词,字符 'a' 是一个随机种子 */
/* 创建新的信号量集合 */
id = (, 1, | |0666);
(“ id=%d/n”, id);
.val = 1; /*设置变量的值 */
(id, 0, , );/* 设置索引 0 的信号量 */
/*打印出信号量的值*/
i = (id, 0, , 0);
(“索引 0 的值为 %d/n”, i);
/*重置信号量*/
. = 0; /*设置哪个信号量*/
. = -1; /*定义操作*/
. = ; /*操作模式*/
if (semop(id, &, 1) == -1) {
(“无法锁定 ./n”);
退出 (1);
i = (id, 0, , 0);
(“索引 0 的值为 %d/n”, i);
/*清除信号量*/
(id, 0, , 0);
扫一扫在手机端查看
-
Tags : linux系统获取进程间的所有通信
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。