第三篇文档:自助终端全自动生产线 —— 建造者模式封装 System V 信号量完整工程实现

第三篇文档:自助终端全自动生产线 —— 建造者模式封装 System V 信号量完整工程实现 文档定位核心工程实现结合设计模式思想分步构建信号量对象完整代码、流程拆解、类比、思维导图可直接用于企业项目。一、趣味类比建造者 银行自助终端生产线老式封装一次性把所有材料塞进机器无法自定义选配 建造者模式生产线拆分 4 个独立工序分步自由配置最后一键生成完整银行信号量集工序 1Builder 初始化新建空白终端工序 2选配银行门牌号key 配置ftok 私有 / IPC_PRIVATE工序 3设置窗口总数、每个窗口初始工位工序 4选配创建权限、标志位IPC_CREAT/IPC_EXCL工序 5Director 构建所有配置完成一键生成可用银行配套工具内置 P/V、自动销毁、参数校验、错误捕获。建造者模式四大角色对应信号量场景表格建造者角色对应代码模块银行类比Product 产品SemProduct完整配置好的银行信号量实例Builder 抽象建造者SemBuilder自助终端标准操作规范配置接口ConcreteBuilder 具体建造者SemConcreteBuilder实际自助终端实现所有配置步骤Director 指挥者SemDirector大堂经理按流程调度配置生成产品二、完整可运行建造者模式代码c运行#include stdio.h #include stdlib.h #include string.h #include sys/sem.h #include sys/ipc.h #include sys/types.h #include unistd.h #include errno.h // 1. Product 产品完整信号量实例 typedef struct { key_t key; int semid; int sem_cnt; int* init_vals; int mode; // 权限 0666 int flag; // IPC_CREAT / IPC_EXCL } SemProduct; // 产品对外操作接口 void sem_product_p(SemProduct* prod, int idx) { struct sembuf op {idx, -1, 0}; if(semop(prod-semid, op, 1) -1) perror(P op fail); } void sem_product_v(SemProduct* prod, int idx) { struct sembuf op {idx, 1, 0}; if(semop(prod-semid, op, 1) -1) perror(V op fail); } // 销毁产品释放内核堆内存 void sem_product_destroy(SemProduct* prod) { semctl(prod-semid, 0, IPC_RMID); free(prod-init_vals); free(prod); } // 2. 抽象建造者 Builder typedef struct SemBuilder SemBuilder; struct SemBuilder { // 分步配置接口 void (*set_key_ftok)(SemBuilder*, const char*, int proj_id); void (*set_key_private)(SemBuilder*); void (*set_sem_count)(SemBuilder*, int cnt); void (*set_single_init)(SemBuilder*, int idx, int val); void (*set_mode_flag)(SemBuilder*, int mode, int flag); // 构建产品 SemProduct* (*build)(SemBuilder*); // 私有缓存配置 SemProduct* temp_prod; }; // 3. 具体建造者 ConcreteBuilder void set_key_ftok_impl(SemBuilder* b, const char* path, int proj) { b-temp_prod-key ftok(path, proj); } void set_key_private_impl(SemBuilder* b) { b-temp_prod-key IPC_PRIVATE; } void set_sem_count_impl(SemBuilder* b, int cnt) { b-temp_prod-sem_cnt cnt; free(b-temp_prod-init_vals); b-temp_prod-init_vals calloc(cnt, sizeof(int)); } void set_single_init_impl(SemBuilder* b, int idx, int val) { if(idx 0 idx b-temp_prod-sem_cnt) b-temp_prod-init_vals[idx] val; } void set_mode_flag_impl(SemBuilder* b, int mode, int flag) { b-temp_prod-mode mode; b-temp_prod-flag flag; } // 核心构建方法生成可用信号量集 SemProduct* build_impl(SemBuilder* b) { SemProduct* prod b-temp_prod; // 创建信号量集 prod-semid semget(prod-key, prod-sem_cnt, prod-flag | prod-mode); if(prod-semid -1) { perror(semget create fail); return NULL; } // 逐个初始化信号量初始值 for(int i0; iprod-sem_cnt; i) { semctl(prod-semid, i, SETVAL, prod-init_vals[i]); } // 重置临时缓存返回成品 SemProduct* ret malloc(sizeof(SemProduct)); memcpy(ret, prod, sizeof(SemProduct)); ret-init_vals malloc(sizeof(int)*prod-sem_cnt); memcpy(ret-init_vals, prod-init_vals, sizeof(int)*prod-sem_cnt); return ret; } // 创建具体建造者实例 SemBuilder* create_sem_builder() { SemBuilder* b malloc(sizeof(SemBuilder)); b-temp_prod malloc(sizeof(SemProduct)); memset(b-temp_prod, 0, sizeof(SemProduct)); b-temp_prod-init_vals NULL; // 绑定接口实现 b-set_key_ftok set_key_ftok_impl; b-set_key_private set_key_private_impl; b-set_sem_count set_sem_count_impl; b-set_single_init set_single_init_impl; b-set_mode_flag set_mode_flag_impl; b-build build_impl; return b; } // 4. Director 指挥者标准化构建流程 // 场景1构建二元互斥信号量单窗口初始值1 SemProduct* director_build_mutex(SemBuilder* b, const char* path, int proj) { b-set_key_ftok(b, path, proj); b-set_sem_count(b, 1); b-set_single_init(b, 0, 1); b-set_mode_flag(b, 0666, IPC_CREAT); return b-build(b); } // 场景2构建私有多窗口计数信号量 SemProduct* director_build_private_sem(SemBuilder* b, int window_num, int init_val) { b-set_key_private(b); b-set_sem_count(b, window_num); for(int i0; iwindow_num; i) { b-set_single_init(b, i, init_val); } b-set_mode_flag(b, 0600, IPC_CREAT); return b-build(b); } // 主函数测试演示 int main() { // 1. 创建建造者生产线 SemBuilder* builder create_sem_builder(); // 2. 指挥者生成互斥二元信号量 SemProduct* mutex_sem director_build_mutex(builder, ./test.txt, 0x99); if(!mutex_sem) return -1; printf(建造者生成信号量semid %d\n, mutex_sem-semid); // 临界区测试 sem_product_p(mutex_sem, 0); printf(获取互斥锁进入临界区\n); sleep(2); sem_product_v(mutex_sem, 0); printf(释放互斥锁\n); // 销毁资源 sem_product_destroy(mutex_sem); free(builder-temp_prod); free(builder); return 0; }编译运行指令bash运行touch test.txt gcc sem_builder.c -o sem_builder ./sem_builder ipcs -s # 无残留代码自动销毁三、建造者模式工作流程拆解自助终端流水线初始化空白建造者空终端自由分步配置 key、窗口数量、初始工位、权限标志Director 指挥者封装标准化场景互斥锁 / 私有计数信号量业务层无需关心底层配置细节调用 build () 一次性创建内核信号量集并完成初始化返回完整可用产品产品自带 P/V、销毁接口业务代码极简。四、本篇核心思维导图建造者 信号量融合五、建造者模式适配 System V 信号量的独特优势配置解耦创建 key、设置信号量数量、初始化 val、权限标志完全分离按需选配场景复用Director 封装互斥锁、限流计数、私有 IPC 等通用场景业务一行代码创建高扩展后续新增超时 semop、批量操作、信号量查询功能仅新增 Builder 配置接口不改动原有业务代码容错统一所有内核 API 错误捕获统一放在 build 函数内部业务无需重复写 perror资源自动管理产品销毁接口统一释放内核信号量 堆内存杜绝 IPC 资源泄露。六、三篇完整系列总结第一篇吃透 System V 信号量内核原理与原生 API明白底层银行模型第二篇发现原生 API 缺陷实现简易封装找到耦合痛点第三篇引入建造者模式分层解耦工程化封装标准化生产线适配企业多并发同步场景。谢谢