基于建造者模式的信號量與理解建造者模式

信號量是什么?

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.pswp.cn/news/903869.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903869.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903869.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

開閉原則(OCP)

非常棒的問題&#xff01;&#x1f50d; 開閉原則&#xff08;OCP, Open/Closed Principle&#xff09;是軟件設計的核心原則之一&#xff0c;下面我將從定義、意義、優劣分析、Python示例和結構圖五個方面完整解析給你。 &#x1f9e0; 什么是開閉原則&#xff1f; 開閉原則&a…

python數據分析(七):Pandas 數據變形與重塑

Pandas 數據變形與重塑全面指南 1. 引言 在數據分析過程中&#xff0c;我們經常需要將數據從一種結構轉換為另一種結構&#xff0c;以適應不同的分析需求。Pandas 提供了豐富的數據變形與重塑功能&#xff0c;包括旋轉(pivot)、堆疊(stack)、融合(melt)等多種操作。本文將詳細…

Android學習總結之jetpack組件間的聯系

在傳統安卓開發中&#xff0c;UI 組件&#xff08;Activity/Fragment&#xff09;常面臨三個核心問題&#xff1a; 生命周期混亂&#xff1a;手動管理 UI 與數據的綁定 / 解綁&#xff0c;易導致內存泄漏&#xff08;如 Activity 銷毀后回調仍在觸發&#xff09;。數據斷層&am…

C++初階:類和對象(二)

大家好&#xff0c;我是小卡皮巴拉 文章目錄 目錄 一.運算符重載 1.1 基本概念 定義 參數規則 特性 選擇原則 重載要點 二.類的默認成員函數 2.1 構造函數 構造函數的特點 2.2 析構函數 析構函數的特點 2.3 拷貝構造函數 拷貝構造的特點 2.4 拷貝賦值運算符重…

【c++】【STL】priority_queue詳解

目錄 priority_queue的作用priority_queue的接口構造函數emptysizetoppushpopswap priority_queue的實現仿函數&#xff08;函數對象&#xff09;是什么&#xff1f;向上調整算法&#xff08;adjustup&#xff09;向下調整算法&#xff08;adjustdown&#xff09;迭代器構造pus…

測試——用例篇

目錄 1. 測試用例 1.1 概念 2. 設計測試用例的萬能公式 2.1 常規思考逆向思維發散性思維 2.2 萬能公式 3. 設計測試用例例的方法 3.1 基于需求的設計方法 ?編輯 3.2 具體的設計方法 3.2.1 等價類 3.2.2 邊界值 3.2.3 正交法 3.2.4 判定表法 3.2.5 場景法 3.2.6…

銷售總監求職簡歷模板

模板信息 簡歷范文名稱&#xff1a;銷售總監求職簡歷模板&#xff0c;所屬行業&#xff1a;其他 | 職位&#xff0c;模板編號&#xff1a;KREUNY 專業的個人簡歷模板&#xff0c;邏輯清晰&#xff0c;排版簡潔美觀&#xff0c;讓你的個人簡歷顯得更專業&#xff0c;找到好工作…

AE腳本 關鍵幀緩入緩出曲線調節工具 Flow v1.5.0 Win/Mac

Flow是一個非常好用的After Effects腳本,它可以讓你更加輕松自如地調整關鍵幀的速度曲線,無需觸碰老舊復雜的圖形編輯器。 AE腳本介紹 Flow為After Effects帶來了一個簡潔的界面,使自定義動畫曲線變得十分容易,無需深入研究速度和影響力這些讓人困惑的概念 - 只需繪制一個曲線…

ACGRIME:用于全局優化和特征選擇的自適應混沌高斯RIME優化器,附完整版免費代碼

自然現象中&#xff0c;軟冰的形成過程由 Set al. [42] 提出&#xff0c;軟冰是空氣中的過冷水滴在接觸固體物體并凍結時形成的。這種現象發生在特定的氣候條件下&#xff0c;當水蒸氣尚未凝結時&#xff0c;導致冰覆蓋的表面呈現出獨特的樹枝狀和葉子狀景觀。它在軟冰的生長和…

大模型開發學習筆記

文章目錄 大模型基礎大模型的使用大模型訓練的階段大模型的特點及分類大模型的工作流程分詞化(tokenization)與詞表映射 大模型的應用 進階agent的組成和概念planning規劃子任務分解ReAct框架 memory記憶Tools工具\工具集的使用langchain認知框架ReAct框架plan-and-Execute計劃…

4.27-5.4學習周報

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 摘要Abstract一、方法介紹2.Rainbow Memory(RM)2.1多樣性感知內存更新2.2通過數據增強增強樣本多樣性(DA) 二、使用步驟1.實驗概況2.RM核心代碼 總結 摘要 本博客概…

AI Rack架構高速互連的挑戰:損耗設計與信號完整性的設計框架

在AI驅動的時代&#xff0c;系統設計已經從單一PCB的視角&#xff0c;逐步轉向以整個rack為單位來考量。 對于信號完整性而言&#xff0c;焦點以不再局限于單一PCB上的損耗&#xff0c;而是擴展到芯片與芯片之間的端到端互連損耗&#xff08;end-to-end interconnect loss&…

杭電oj(1180、1181)題解

目錄 1180 題目 思路 問題概述 代碼思路分析 1. 數據結構與全局變量 2. BFS 函數 bfs 3. 主函數 main 總結 代碼 1181 題目 思路 1. 全局變量的定義 2. 深度優先搜索函數 dfs 3. 主函數 main 總結 代碼 1180 題目 思路 注&#xff1a;當走的方向和樓梯方向一…

軟件測試概念

這里寫目錄標題 需求開發模型軟件生命周期瀑布模型螺旋模型增量模型、迭代模型敏捷模型Scrum 測試模型V模型W模型&#xff08;雙V模型&#xff09; 需求 用戶需求&#xff1a;沒有經過合理的評估&#xff0c;通常就是一句話 軟件需求&#xff1a;是開發人員和測試人員執行工作…

數字基帶信號和頻帶信號的區別解析

數字基帶信號和數字頻帶信號是通信系統中兩種不同的信號形式&#xff0c;它們的核心區別在于是否經過調制以及適用的傳輸場景。以下是兩者的主要區別和分析&#xff1a; 1. 定義與核心區別 數字基帶信號&#xff08;Digital Baseband Signal&#xff09; 未經調制的原始數字信號…

Linux52 運行百度網盤 解決故障無法訪問repo nosandbox 未解決:疑似libstdc++版本低導致無法運行baidu網盤

昨日參考 哦 我是root Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64 沒了 計劃去手動下一個 還是不行 放棄 猜測是 centos7 過期了 一些依賴組件也沒地方下載了 通過阿里云鏡像站下載 之前安裝的好像不是這個版本 還是計劃用yum去下載依賴&#xff0c;先處…

2000-2022年上市公司數字經濟專利申請數據

2000-2022年上市公司數字經濟專利申請數據 1、時間&#xff1a;2000-2022年 2、來源&#xff1a;國家知識產權局 3、指標&#xff1a;年份、股票代碼、股票簡稱、行業名稱、行業代碼、省份、城市、區縣、行政區劃代碼、城市代碼、區縣代碼、首次上市年份、上市狀態、數字經濟…

機器學習之五:基于解釋的學習

正如人們有各種各樣的學習方法一樣&#xff0c;機器學習也有多種學習方法。若按學習時所用的方法進行分類&#xff0c;則機器學習可分為機械式學習、指導式學習、示例學習、類比學習、解釋學習等。這是溫斯頓在1977年提出的一種分類方法。 有關機器學習的基本概念&#xff0c;…

Chromium 134 編譯指南 - Android 篇:安裝構建依賴項(七)

1. 引言 歡迎來到《Chromium 134 編譯指南》系列的第七篇文章&#xff01;在前面的章節中&#xff0c;我們已經成功獲取了Chromium源代碼&#xff0c;并將其配置為支持Android平臺。這些步驟為我們的編譯之旅奠定了堅實的基礎&#xff0c;但在開始實際編譯之前&#xff0c;我們…

java 進階 1.0

靜態方法 static 就是能直接用&#xff0c;不用再new一個對象了 一般java中Math等靜態類就是可以直接使用其方法 main函數里面不能包含太多的邏輯性語句&#xff0c;全部寫成模塊 寫好程序之后如何測試呢&#xff1f; 使用junit&#xff0c;不能在main函數里測試 測試本身就…