我们已经准备好了,你呢?

2024我们与您携手共赢,为您的企业形象保驾护航!

这里绝对不可能详细描述进程间的通信,也很难自信地说出自己在这部分内容中达到了什么样的理解,所以在本节的开头,我首先向大家推荐这位著名作者的名作:《在 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);

二维码
扫一扫在手机端查看

本文链接:https://by928.com/7925.html     转载请注明出处和本文链接!请遵守 《网站协议》
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。

项目经理在线

我们已经准备好了,你呢?

2020我们与您携手共赢,为您的企业形象保驾护航!

在线客服
联系方式

热线电话

13761152229

上班时间

周一到周五

公司电话

二维码
微信
线