当前位置: 首页 > news >正文

基于建造者模式的信号量与理解建造者模式

信号量是什么?

AI解释:信号量(Semaphore)是操作系统中用于 进程同步与互斥 的经典工具,由荷兰计算机科学家 Edsger Dijkstra 在 1965 年提出。它本质上是一个 非负整数变量,通过原子操作(P 操作和 V 操作)实现对共享资源的访问控制。

System-V版本的信号量相关API:

Ftok

函数定义:
key_t ftok(const char *pathname, int proj_id);
函数作用:

获取唯一的key值标识符。

参数解释:
  • 传入一个有效的文件路径和一个 <255 的整数数字,返回一个具有唯一性的 key

semget

函数定义:
int semget(key_t key, int nsems, int semflg);
函数作用:

获取或者创建信号量集的文件描述符 fd

参数解释:
  • keyftok 调用成功返回的 key
  • nsems:要创建/获取的信号量集合中的信号量数量 cnt
  • semflg
    • 传入 (IPC_CREATE | IPC_EXCL | 文件权限) 表示创建信号量集合,并返回 fd
    • 传入 IPC_CREATE 表示获取指定的信号量集合 fd

semctl

函数定义:
int semctl(int semid, int semnum, int cmd, ...);
函数作用:

控制指定的信号量集合,删除或者修改。

参数解释:
  • semid:指定的信号量集的文件描述符 fd
  • semnum:要控制的信号量集合中的下标(数组下标从0开始)。
  • cmd
    • 设置为 IPC_RMID 时,表示删除指定信号量集,可忽略 semnum(设为0)和可变参数。
    • 设置为 SETVAL 时,表示设置信号量的值,需手动创建联合体 union semun 并设置 val 字段:
      union semun {int val;               /* Value for SETVAL */struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL */struct seminfo *__buf; /* Buffer for IPC_INFO */
      } sem_un;
      sem_un.val = val; // 设置val字段
      semctl(fd, i, SETVAL, sem_un); // 传入可变参数
      

semop

函数定义:
int semop(int semid, struct sembuf *sops, unsigned nsops);
函数作用:

对信号量进行 PV 操作。

PV操作:

使用系统提供的 struct sembuf 结构体:

struct sembuf {unsigned short sem_num;  /* 信号量下标 */short          sem_op;   /* 操作值(-1为P操作,1为V操作) */short          sem_flg;  /* 标志,一般设为SEM_UNDO */
};
参数解释:
  • sem_num:信号量集合中信号量的下标。
  • sem_op-1 表示 P 操作,1 表示 V 操作(本质是对信号量值进行加减)。
  • sem_flg:一般设置为 SEM_UNDO,表示异常时销毁信号量。
  • semid:信号量集描述符。
  • sopsstruct sembuf 数组地址,支持批量 PV 操作。
  • nsops:数组大小。

实现基于简单建造者模式的信号量封装

日志模块 gitee:https://gitee.com/LOG_C/log

#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <string.h>
#include "Log.hpp"
using namespace ns_log;#define CREATE_SEM (IPC_CREAT | IPC_EXCL | 0666)
#define GET_SEM (IPC_CREAT)
#define P_OP (-1) /* P操作 */
#define V_OP (1)  /* V操作 */
const std::string SEM_PATH = "../tmp"; // 需要先创建有效目录
const int proj_id = 123;
const int default_sem_nums = 1;std::string ToHex(int num) {char buf[64];sprintf(buf, "0x%x", num);return buf;
}class Semaphore {
private:int _fd;void PV(int op) {struct sembuf sem_buf;sem_buf.sem_num = 0;sem_buf.sem_op = op;sem_buf.sem_flg = SEM_UNDO;int n = semop(_fd, &sem_buf, 1);if (n < 0) {LOG(DEBUG, "op = %d失败\n", op);return;}}public:Semaphore(int fd) : _fd(fd) {}void P() { PV(P_OP); LOG(DEBUG, "P操作done\n"); }void V() { PV(V_OP); LOG(DEBUG, "V操作done\n"); }~Semaphore() {if (_fd > 0) {int n = semctl(_fd, 0, IPC_RMID);if (n < 0) {LOG(ERROR, "semctl的IPC_RMID操作异常!,异常信息:%s\n", strerror(errno));}LOG(DEBUG, "销毁信号量done\n");}}
};
using SemPtr = std::shared_ptr<Semaphore>;class SemaphoreBuilder {
private:int _val;bool Init(int fd, int num, int val) {union semun {int val;struct semid_ds *buf;unsigned short *array;struct seminfo *__buf;} sem_un;sem_un.val = val;for (int i = 0; i < num; i++) {int ret = semctl(fd, i, SETVAL, sem_un);if (ret < 0) {LOG(ERROR, "semctl的SETVAL操作异常!,异常信息:%s\n", strerror(errno));return false;}}return true;}public:SemaphoreBuilder() {}SemaphoreBuilder& SetVal(int val) { _val = val; return *this; }SemPtr Build(int flag, int num = default_sem_nums) {LOG(DEBUG, "开始build信号量\n");key_t key = ftok(SEM_PATH.c_str(), proj_id);if (key == -1) {LOG(ERROR, "ftok操作异常!,异常信息:%s\n", strerror(errno));return nullptr;}LOG(INFO, "frok的key为:%s\n", ToHex(key).c_str());int sem_fd = semget(key, num, flag);if (sem_fd == -1) {LOG(ERROR, "semget操作异常!,异常信息:%s\n", strerror(errno));return nullptr;}if (flag == CREATE_SEM) {Init(sem_fd, num, _val);}return std::make_shared<Semaphore>(sem_fd);}
};

理解建造者模式

定义:

将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。通过分解复杂对象的构建步骤,每一步创建一部分,最后组合成完整对象。

角色:

  1. 产品(Product)
    • 被构建的复杂对象,包含多个组成部分(属性和行为)。
  2. 抽象建造者(Builder)
    • 定义构建复杂对象各部分的接口,以及返回最终产品的方法。
  3. 具体建造者(Concrete Builder)
    • 实现抽象建造者接口,具体构建对象的各部分,生成不同类型或形式的产品。
  4. 指挥者(Director)
    • 负责调用具体建造者构建对象,不依赖具体类,仅通过建造者接口操作。

重构后的建造者模式(信号量场景)

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <string.h>
#include "Log.hpp"
using namespace ns_log;#define CREATE_SEM (IPC_CREAT | IPC_EXCL | 0666)
#define GET_SEM (IPC_CREAT)
#define P_OP (-1) /* P操作 */
#define V_OP (1)  /* V操作 */
const std::string SEM_PATH = "../tmp";
const int proj_id = 123;
const int default_sem_nums = 1;enum { FTOK_ERROR = 1, SEMGET_ERROR, SEMCTL_ERROR };std::string ToHex(int num) {char buf[64];sprintf(buf, "0x%x", num);return buf;
}// 产品:信号量
class Semaphore {
private:int _fd;void PV(int who, int op) {struct sembuf sem_buf;sem_buf.sem_num = who;sem_buf.sem_op = op;sem_buf.sem_flg = SEM_UNDO;int n = semop(_fd, &sem_buf, 1);if (n < 0) {LOG(DEBUG, "op = %d失败\n", op);return;}}public:Semaphore(int fd) : _fd(fd) {}void P(int who) { PV(who, P_OP); LOG(DEBUG, "P操作done\n"); }void V(int who) { PV(who, V_OP); LOG(DEBUG, "V操作done\n"); }int Fd() const { return _fd; }~Semaphore() {if (_fd > 0) {int n = semctl(_fd, 0, IPC_RMID);if (n < 0) {LOG(ERROR, "semctl的IPC_RMID操作异常!,异常信息:%s\n", strerror(errno));}LOG(DEBUG, "销毁信号量done\n");}}
};// 抽象建造者
class Builder {
public:virtual ~Builder() {}virtual void BuildKey() = 0;         // 获取键值virtual void SetPerm(int perm) = 0;  // 设置权限virtual void SetSemNum(int num) = 0; // 设置信号量数量virtual void SetVal(const std::vector<int>& init_vals) = 0; // 初始化值virtual void Init() = 0;             // 初始化信号量virtual void Build(int flag) = 0;     // 构建信号量
};// 具体建造者
class SemaphoreBuilder : public Builder {
private:bool init(int fd, int index, int val) {union semun {int val;struct semid_ds *buf;unsigned short *array;struct seminfo *__buf;} sem_un;sem_un.val = val;int ret = semctl(fd, index, SETVAL, sem_un);if (ret < 0) {LOG(ERROR, "semctl的SETVAL操作异常!,异常信息:%s\n", strerror(errno));return false;}return true;}public:std::shared_ptr<Semaphore> GetSemaphore() { return _sem; }void BuildKey() override {_key = ftok(SEM_PATH.c_str(), proj_id);if (_key == -1) {LOG(ERROR, "ftok操作异常!,异常信息:%s\n", strerror(errno));exit(FTOK_ERROR);}LOG(INFO, "frok的key为:%s\n", ToHex(_key).c_str());}void SetPerm(int perm) override { _perm = perm; }void SetSemNum(int num) override { _sem_cnts = num; }void SetVal(const std::vector<int>& init_vals) override { _init_vals = init_vals; }void Init() override {if (_sem_cnts > 0 && _sem_cnts == _init_vals.size()) {for (int i = 0; i < _sem_cnts; i++) {if (!init(_sem->Fd(), i, _init_vals[i])) {exit(SEMCTL_ERROR);}}}}void Build(int flag) override {int sem_fd = semget(_key, _sem_cnts, flag);if (sem_fd == -1) {LOG(ERROR, "semget操作异常!,异常信息:%s\n", strerror(errno));exit(SEMGET_ERROR);}_sem = std::make_shared<Semaphore>(sem_fd);}private:std::shared_ptr<Semaphore> _sem;key_t _key;int _perm;int _sem_cnts;std::vector<int> _init_vals;
};// 指挥者
class Director {
public:void construct(std::shared_ptr<SemaphoreBuilder>& sem_builder,int flag,int num,const std::vector<int>& vals,int perm) {sem_builder->BuildKey();sem_builder->SetPerm(perm);sem_builder->SetVal(vals);sem_builder->SetSemNum(num);sem_builder->Build(flag);if (flag == CREATE_SEM) {sem_builder->Init();}}
};
http://www.xdnf.cn/news/251875.html

相关文章:

  • Linux架构篇、第一章_03安装部署nginx
  • 第二十周:项目开发中遇到的相关问题(一)
  • 深入理解 MyBatis 代理机制
  • 使用mybatis实例类和MySQL表的字段不一致怎么办
  • 软件测试概念
  • 本地大模型编程实战(32)用websocket显示大模型的流式输出
  • smss源代码分析之smss!SmpLoadSubSystemsForMuSession函数分析加载csrss.exe
  • 全感官交互革命:当 AI 大模型学会 “看、听、说、创”
  • 滑动窗口leetcode 209和76
  • rabbitMQ如何确保消息不会丢失
  • [学成在线]22-自动部署项目
  • 【Git】万字详解 Git 的原理与使用(上)
  • 精益数据分析(37/126):深度剖析SaaS模式下的参与度与流失率指标
  • STM32——GPIO
  • AI 生成内容的版权困境:法律、技术与伦理的三重挑战
  • patch命令在代码管理中的应用
  • C++负载均衡远程调用学习之UDP SERVER功能
  • react + antd 实现后台管理系统
  • TS 常用类型
  • C++-Lambda表达式
  • MySQL 窗口函数
  • 使用conda安装Python库包报错:module ‘libmambapy‘ has no attribute ‘QueryFormat‘
  • SpringBoot实现条件分页
  • ROPE(旋转位置编码)简述
  • 数据库性能杀手与调优实践
  • 第十六届蓝桥杯单片机组省赛(第一套)
  • 解决 3D Gaussian Splatting 中 SIBR 可视化组件报错 uv_mesh.vert 缺失问题【2025最新版!】
  • 基于深度学习的毒蘑菇检测
  • 大学生入学审核系统设计与实现【基于SpringBoot + Vue 前后端分离技术】
  • 精益数据分析(38/126):SaaS模式的流失率计算优化与定价策略案例