做网站的用户需求分析,物业管理系统功能,服装培训网站建设,wordpress插件ssh文章目录 前言#xff1a;#x1f383;消息队列#xff1a;1. **消息队列的基本概念**2. **消息队列的特点**3. **常见的消息队列操作#xff08;Linux IPC#xff09;****1) msgget#xff1a;创建或获取消息队列****2) msgsnd#xff1a;发送消息****3) msgrcv#x… 文章目录 前言消息队列1. **消息队列的基本概念**2. **消息队列的特点**3. **常见的消息队列操作Linux IPC****1) msgget创建或获取消息队列****2) msgsnd发送消息****3) msgrcv接收消息****4) msgctl控制消息队列** 4. **消息队列的基本操作示例Linux C代码****消息发送示例****消息接收示例****删除消息队列** 5. **消息队列的优缺点****优点****缺点** 6. **消息队列的应用场景** 信号量❤️五个概念❤️对信号量的理解对于不整体使用的资源对于整体使用的资源那我可不可以使用全局变量 OS是如何把共享内存、消息队列、信号量统一管理起来的 前言
关于System V下的通信方式我们只是对共享内存做深度的处理而对于消息队列和信号量我们并不会特别在意一下我将粗略的介绍一下关于消息队列但是信号量这一部分还有一些新的知识点需要好好聊聊。
消息队列
消息队列Message Queue是操作系统提供的一种进程间通信IPCInter-Process Communication机制允许进程通过消息的形式进行异步通信。消息队列为进程间提供了一个有序的、独立于进程之外的消息缓冲区进程可以通过向消息队列发送和接收消息来进行数据交换。
1. 消息队列的基本概念
异步通信消息发送进程和接收进程之间是异步的即发送者可以发送消息后立即返回无需等待接收者处理同样接收者在准备好时可以读取消息而无需等待发送者。持久性消息队列中的消息是持久的消息一旦被发送它们会保留在队列中直到被接收进程读取或队列被显式删除。顺序性消息以队列的形式存储发送的顺序决定了消息的顺序。接收者可以按照消息的优先级或先进先出的顺序读取消息。
2. 消息队列的特点
异步通信消息队列允许发送进程和接收进程以不同时执行发送进程不需要等待接收进程处理消息。持久性消息队列是内核管理的在消息被读取之前它们会一直保存在队列中即使发送者和接收者都已经终止。消息有优先级消息可以按照优先级或FIFO先进先出的方式传递接收者可以按优先级顺序或按时间顺序接收消息。
3. 常见的消息队列操作Linux IPC
在Linux中消息队列是通过系统调用来实现的。下面是与消息队列相关的常见系统调用及其功能
1) msgget创建或获取消息队列
int msgget(key_t key, int msgflg);key消息队列的唯一标识符由用户定义。可以通过ftok()函数生成。msgflg消息队列的标志位。可以是IPC_CREAT如果消息队列不存在则创建以及权限标志如0666等。返回值返回消息队列的标识符msqid后续操作基于此ID。
2) msgsnd发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);msqid消息队列标识符由msgget()返回。msgp指向消息结构体的指针该结构体包含消息类型和消息内容。msgsz消息的大小。msgflg控制操作的标志位。如果队列满了IPC_NOWAIT可以避免发送者被阻塞。返回值成功时返回0失败时返回-1并设置errno。
消息结构通常定义如下
struct msgbuf {long mtype; // 消息类型char mtext[1]; // 消息内容
};3) msgrcv接收消息 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);msqid消息队列标识符。msgp指向存储接收消息的结构体的指针。msgsz要接收的最大消息大小。msgtyp指定要接收的消息类型。如果为0则接收队列中的第一条消息。msgflg控制操作的标志位。可以使用IPC_NOWAIT来防止阻塞或者使用MSG_EXCEPT来接收非指定类型的消息。返回值返回读取到的字节数失败时返回-1并设置errno。
4) msgctl控制消息队列 int msgctl(int msqid, int cmd, struct msqid_ds *buf);msqid消息队列标识符。 cmd 控制操作可以是以下值 IPC_STAT获取消息队列的状态。IPC_SET设置消息队列的状态。IPC_RMID删除消息队列。 buf用于存储或设置消息队列的状态信息msqid_ds结构体包含权限、最后的操作时间、消息数等信息。
4. 消息队列的基本操作示例Linux C代码
以下是一个简单的消息队列示例代码展示如何创建消息队列、发送消息和接收消息。
消息发送示例
c复制代码#include stdio.h
#include sys/ipc.h
#include sys/msg.h
#include string.hstruct msgbuf {long mtype; // 消息类型char mtext[100]; // 消息内容
};int main() {key_t key;int msgid;// 生成唯一的keykey ftok(progfile, 65);// 创建消息队列msgid msgget(key, 0666 | IPC_CREAT);// 准备要发送的消息struct msgbuf message;message.mtype 1; // 消息类型strcpy(message.mtext, Hello World!);// 发送消息到队列msgsnd(msgid, message, sizeof(message.mtext), 0);printf(Message Sent: %s\n, message.mtext);return 0;
}消息接收示例
c复制代码#include stdio.h
#include sys/ipc.h
#include sys/msg.hstruct msgbuf {long mtype; // 消息类型char mtext[100]; // 消息内容
};int main() {key_t key;int msgid;// 生成唯一的keykey ftok(progfile, 65);// 获取消息队列msgid msgget(key, 0666 | IPC_CREAT);// 准备接收消息struct msgbuf message;// 接收类型为1的消息msgrcv(msgid, message, sizeof(message.mtext), 1, 0);// 显示消息内容printf(Message Received: %s\n, message.mtext);return 0;
}删除消息队列
c复制代码#include sys/ipc.h
#include sys/msg.hint main() {key_t key;int msgid;// 生成唯一的keykey ftok(progfile, 65);// 获取消息队列msgid msgget(key, 0666 | IPC_CREAT);// 删除消息队列msgctl(msgid, IPC_RMID, NULL);return 0;
}5. 消息队列的优缺点
优点
异步处理发送进程不必等待接收进程可以提高系统的并发性和响应能力。持久性消息在队列中保存直到接收者取走消息或队列被删除即使发送者和接收者的生命周期不同步。易用性消息队列通过消息类型支持不同的消息分类允许接收进程选择性读取某一类型的消息。
缺点
容量限制消息队列有大小限制如果消息队列已满发送进程可能会被阻塞除非设置非阻塞标志。管理复杂性消息队列是内核资源使用后需要手动清理未清理的消息队列可能会长期占用系统资源。不适合大量数据传输消息队列更适合传递较小的数据过大的数据块可能会影响系统性能。
6. 消息队列的应用场景
进程间通信消息队列用于不同进程之间的数据交换例如不同模块之间的数据传递。任务调度某些系统通过消息队列进行任务调度工作进程从队列中取任务执行。日志系统系统日志可以通过消息队列集中到一个日志处理进程来进行统一的日志存储或分析。
消息队列是一种常用的进程间通信机制支持异步数据传输和灵活的消息管理。通过msgget、msgsnd、msgrcv等系统调用进程可以方便地将消息发送到队列中并从中读取消息。虽然消息队列有一些限制比如队列大小的限制和内核资源的消耗但它在许多系统中仍然是一个高效的通信工具。
信号量
❤️五个概念
多个进程执行流想要实现通信都必须在内核中看到同一份资源这个资源成为公共资源共享资源。而被保护起来的资源就叫——临界资源而保护的方式分为同步和互斥而互斥是任何一个时刻只能有一个进程在访问公共资源。而以互斥方式保护的共享资源就是临界资源。资源一定是要被访问的而且是通过代码访问的。代码又会分为“存在访问共享资源的”和“不存在访问共享资源的”。对于上述这两种情况分别称为——临界区和非临界区。所谓利用互斥保护共享资源使其变为临界资源本质是对访问共享资源的代码进行保护。
❤️对信号量的理解
信号量Semaphore是一种用于控制对共享资源的访问的同步机制广泛应用于多线程和多进程编程中。信号量可以用来解决临界区问题防止竞争条件并确保资源的互斥访问。简单来说是用来保护临界资源的
对于不整体使用的资源 所以对临界资源的保护其实就是设置一个计数器每次访问前先申请访问访问通过了才能访问访问完成后又会有一个退出操作。因此保护临界资源的信号量本质就是一个计数器 电影院临界资源 买票申请信号量 ———— 本质就是对公共资源的一种预定机制 票数信号量的初始值 步骤 申请信号量访问临界资源释放信号量 对于整体使用的资源 那我可不可以使用全局变量
意思是既然信号量是一个计数器那我可不可以直接使用一个全局变量来表示计数器想着可不可以完全替代信号量呢
————不能 全局变量不能被所有进程看到因为进程之间具有独立性而父子进程却很有可能发生写实拷贝。 不是原子的。 什么是原子操作 **原子操作Atomic Operation**是指一个操作要么完整地执行要么完全不执行。在多线程/多进程环境下原子操作可以确保操作的完整性不会被其他线程/进程打断。
而使用全局变量作为计数器时增加和减少计数的操作通常需要多个步骤比如:
读取全局变量的值对值进行修改将修改后的值写回全局变量
这三个步骤并不是一个原子操作。在多线程/进程环境下,如果两个线程/进程同时执行这三个步骤,就可能出现竞争条件(race condition),导致计数器的值不准确。
比如:
进程A读取计数器值为10进程B也读取计数器值为10进程A将值加1写回为11进程B将值加1写回为11
此时,计数器的值应该是12,但实际只变成了11,出现了错误。
所以还得是信号量不能是任何什么全局变量这种非原子的。 所以就得让多个进程看到一个信号量计数器 那就说明这个信号量本质就是一个公共资源 既然你作为信号量你的任务是保证其它临界资源的安全那首先你得保证自己是安全的 有很多方法保证信号量自身是安全的那些操作我们以后讲不过现在我们可以就原子性来讲讲。 信号量的核心操作 P(wait) 和 V(signal) 都是原子操作。 即这些操作要么完全执行,要么完全不执行,中间不会被中断再按照上面局列举的例子就能理解如何保护临界资源的。
OS是如何把共享内存、消息队列、信号量统一管理起来的
先组织再描述 struct kern_ipc_perm 是在 Linux 内核中用于管理进程间通信IPC对象的权限结构体。它是内核中 ipc_perm 的扩展版本特意用于对共享内存、消息队列、信号量等 System V IPC 机制进行权限管理和控制。在用户空间中ipc_perm 提供的是一个简化版的权限结构而 kern_ipc_perm 则是内核用来管理这些权限的完整结构。
struct ipc_id_ary 是 Linux 内核中用于管理 System V IPC 对象如共享内存、消息队列、信号量的数据结构之一。它的主要作用是管理和跟踪所有的 IPC 资源并存储这些 IPC 资源的标识符和相关信息。
IPC进程间通信资源在内核中通常通过索引和标识符shmid、msqid、semid 等进行管理。ipc_id_ary 是一个数组结构用于保存 IPC 资源的 ID 和对应的数据结构通常包括每种 IPC 对象类型共享内存、消息队列、信号量的标识符和状态信息。 你每创建一个共享内存或者消息队列本质就是先进行一次struct kern_ipc_perm对象实例化这里包含了该共享内存的key和序列号seq而struct kern_ipc_perm每次的创建都会由struct ipc_id_ary里的柔性数组做管理这里就是你每一次创建一个共享内存我这里的下标就会加一这也就是为什么你每次拿到shmid都会在上次的基础上加一因此shmid本质就是struct ipd_id_ary里的柔性数组的下标而每当你释放共享内存。 序列号的递增共享内存段删除时内核不会重新使用之前的序列号。相反它会递增序列号这样下次创建共享内存段时即使使用相同的索引位置生成的 shmid 也不同。 避免重复使用相同的 shmid递增序列号的目的是为了防止系统意外地重新使用旧的 shmid。这可以防止进程在使用过期或无效的 shmid 时产生意外行为。 现在我们可以说完成了进程间通信的话题管道是在内核中对缓冲区实现通信命名管道则是对文件共享内存则是对一个数组不过是在用户层面上的。下一章我们将开启Linux信号。