📌 核心结论(TL;DR):
System V 缺陷:接口(
semget/msgget)极其反人类,且生命周期随内核,不手动删就会导致资源泄漏。信号量(Semaphore):本质是一个计数器。P 操作(申请资源,减1),V 操作(释放资源,加1)。使用建造者模式(Builder)可以优雅地初始化信号量集合。
消息队列(Message Queue):支持带“类型”的数据块(实现优先级)。使用责任链模式(Chain of Responsibility)可以流水线式处理消息(格式化 -> 落盘 -> 备份)。
清理命令:
ipcs -s/ipcs -q查看,ipcrm -s <id>/ipcrm -q <id>手动删除。
一、 为什么需要设计模式?
原生的 System V IPC 接口(如 semctl 中的 union semun 构造)非常繁琐。如果在业务代码里直接调用,会导致代码极其臃肿。我们利用经典的设计模式对这些系统调用进行二次封装。
二、 信号量:基于建造者模式封装
信号量(Semaphore)用于多进程/多线程间的同步与互斥。因为它涉及的参数较多(Key生成、创建标志、初始值设定),这里引入建造者模式。
// 核心思想:链式调用,最后 Build 出对象
class SemaphoreBuilder {
public:
SemaphoreBuilder& SetVal(int val) { _val = val; return *this; }
sem_sptr Build(int flag) {
// 内部完成 ftok, semget, semctl 的初始化
// ...
return std::make_shared<Semaphore>(semid, flag);
}
};
// 使用方式极其优雅:
SemaphoreBuilder sb;
auto fsem = sb.SetVal(1).Build(BUILD_SEM);
fsem->P(); // 加锁
fsem->V(); // 解锁
三、 消息队列:基于责任链模式封装
消息队列允许进程发送带有 mtype(类型)的数据块。假设我们有这样一个需求:客户端发来消息,我们需要依次经过“拼接时间格式化” -> “写入文件持久化” -> “判断文件大小,过大则打包备份”。
用 if-else 写会很乱,引入责任链模式(Chain of Responsibility)。
// 1. 抽象处理者
class HandlerText {
public:
void SetNextHandler(std::shared_ptr<HandlerText> handler) { _next_handler = handler; }
virtual void Execute(std::string &info) = 0;
protected:
std::shared_ptr<HandlerText> _next_handler;
};
// 2. 具体处理者:格式化
class HandlerTextFormat : public HandlerText {
void Execute(std::string &info) override {
// 处理逻辑:拼接时间
info = time_str + info;
if (_next_handler) _next_handler->Execute(info); // 交给下一个节点
}
};
// 3. 具体处理者:写文件
class HandlerTextSaveFile : public HandlerText {
void Execute(std::string &info) override {
// 处理逻辑:写文件
if (_next_handler) _next_handler->Execute(info);
}
};
// 4. 组装责任链
_format->SetNextHandler(_save);
_save->SetNextHandler(_backup);
_format->Execute(msg); // 只要触发头部,整个流水线就会自动跑起来
四、 避坑指南:资源清理
System V IPC 对象(共享内存、消息队列、信号量)的生命周期随内核。即使创建它们的进程崩溃了,资源也会一直留在系统里。
ipcs -q # 查看消息队列
ipcs -s # 查看信号量
ipcrm -q <msqid> # 删除指定的消息队列
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/weixin_54085376/article/details/168979547




