C語言-發布訂閱模式詳解與實踐

文章目錄

  • C語言發布訂閱模式詳解與實踐
    • 1. 什么是發布訂閱模式?
    • 2. 為什么需要發布訂閱模式?
    • 3. 實際應用場景
    • 4. 代碼實現
      • 4.1 UML 關系圖
      • 4.2 頭文件 (pubsub.h)
      • 4.3 實現文件 (pubsub.c)
      • 4.4 使用示例 (main.c)
    • 5. 代碼分析
      • 5.1 關鍵設計點
      • 5.2 實現特點
    • 6. 編譯和運行
    • 7. 注意事項
    • 8. 改進建議
    • 9. 總結
    • 參考資料

C語言發布訂閱模式詳解與實踐

1. 什么是發布訂閱模式?

發布訂閱模式定義了一種一對多的依賴關系,讓多個訂閱者對象同時監聽某一個主題。這個主題在狀態發生變化時,會通知所有依賴于它的訂閱者對象,使它們能夠自動更新。

2. 為什么需要發布訂閱模式?

  • 實現對象間的松耦合
  • 支持廣播通信
  • 動態訂閱和取消訂閱
  • 事件驅動架構
  • 異步消息處理

3. 實際應用場景

  • 傳感器數據分發
  • 消息隊列系統
  • 事件處理系統
  • 日志監控
  • 狀態更新通知

4. 代碼實現

4.1 UML 關系圖

Publisher
+publish()
+subscribe()
+unsubscribe()
Subscriber
+update()
Topic
+name
+data

4.2 頭文件 (pubsub.h)

#ifndef PUBSUB_H
#define PUBSUB_H#include <stdint.h>
#include <stdbool.h>// 主題數據結構
typedef struct {char name[32];          // 主題名稱void* data;            // 主題數據uint32_t data_size;    // 數據大小uint32_t timestamp;    // 時間戳
} Topic;// 訂閱者回調函數類型
typedef void (*SubscriberCallback)(const Topic* topic, void* user_data);// 訂閱者結構
typedef struct {char name[32];              // 訂閱者名稱SubscriberCallback callback; // 回調函數void* user_data;            // 用戶數據
} Subscriber;// 發布者結構
typedef struct {char name[32];              // 發布者名稱Subscriber* subscribers[16]; // 訂閱者列表int subscriber_count;       // 訂閱者數量
} Publisher;// 創建發布者
Publisher* create_publisher(const char* name);// 銷毀發布者
void destroy_publisher(Publisher* publisher);// 訂閱主題
bool subscribe(Publisher* publisher, const char* subscriber_name,SubscriberCallback callback,void* user_data);// 取消訂閱
bool unsubscribe(Publisher* publisher, const char* subscriber_name);// 發布主題
void publish(Publisher* publisher, const Topic* topic);#endif // PUBSUB_H

4.3 實現文件 (pubsub.c)

#include "pubsub.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>Publisher* create_publisher(const char* name) {Publisher* publisher = (Publisher*)malloc(sizeof(Publisher));strncpy(publisher->name, name, sizeof(publisher->name) - 1);publisher->subscriber_count = 0;memset(publisher->subscribers, 0, sizeof(publisher->subscribers));return publisher;
}void destroy_publisher(Publisher* publisher) {if (!publisher) return;// 釋放所有訂閱者for (int i = 0; i < publisher->subscriber_count; i++) {free(publisher->subscribers[i]);}free(publisher);
}bool subscribe(Publisher* publisher, const char* subscriber_name,SubscriberCallback callback,void* user_data) {if (!publisher || !subscriber_name || !callback) return false;// 檢查是否已達到最大訂閱者數量if (publisher->subscriber_count >= 16) {printf("訂閱者數量已達上限\n");return false;}// 檢查是否已訂閱for (int i = 0; i < publisher->subscriber_count; i++) {if (strcmp(publisher->subscribers[i]->name, subscriber_name) == 0) {printf("訂閱者 %s 已存在\n", subscriber_name);return false;}}// 創建新訂閱者Subscriber* subscriber = (Subscriber*)malloc(sizeof(Subscriber));strncpy(subscriber->name, subscriber_name, sizeof(subscriber->name) - 1);subscriber->callback = callback;subscriber->user_data = user_data;// 添加到訂閱者列表publisher->subscribers[publisher->subscriber_count++] = subscriber;printf("訂閱者 %s 已添加\n", subscriber_name);return true;
}bool unsubscribe(Publisher* publisher, const char* subscriber_name) {if (!publisher || !subscriber_name) return false;for (int i = 0; i < publisher->subscriber_count; i++) {if (strcmp(publisher->subscribers[i]->name, subscriber_name) == 0) {// 釋放訂閱者free(publisher->subscribers[i]);// 移動后續訂閱者for (int j = i; j < publisher->subscriber_count - 1; j++) {publisher->subscribers[j] = publisher->subscribers[j + 1];}publisher->subscriber_count--;printf("訂閱者 %s 已移除\n", subscriber_name);return true;}}printf("未找到訂閱者 %s\n", subscriber_name);return false;
}void publish(Publisher* publisher, const Topic* topic) {if (!publisher || !topic) return;printf("\n發布者 %s 發布主題 %s\n", publisher->name, topic->name);// 通知所有訂閱者for (int i = 0; i < publisher->subscriber_count; i++) {Subscriber* subscriber = publisher->subscribers[i];printf("通知訂閱者 %s\n", subscriber->name);subscriber->callback(topic, subscriber->user_data);}
}

4.4 使用示例 (main.c)

#include "pubsub.h"
#include <stdio.h>// 溫度傳感器訂閱者回調
void temperature_callback(const Topic* topic, void* user_data) {float* threshold = (float*)user_data;float temperature = *(float*)topic->data;printf("溫度傳感器收到數據: %.1f°C\n", temperature);if (temperature > *threshold) {printf("警告:溫度超過閾值 %.1f°C!\n", *threshold);}
}// 日志記錄訂閱者回調
void logger_callback(const Topic* topic, void* user_data) {printf("日志記錄器:主題 %s, 數據大小 %d, 時間戳 %d\n",topic->name, topic->data_size, topic->timestamp);
}int main() {// 創建發布者Publisher* sensor_publisher = create_publisher("傳感器發布者");// 創建溫度閾值float temp_threshold = 30.0f;// 訂閱主題subscribe(sensor_publisher, "溫度監控器", temperature_callback, &temp_threshold);subscribe(sensor_publisher, "系統日志", logger_callback, NULL);// 創建并發布溫度數據float temp_data[] = {25.5f, 28.3f, 32.7f};for (int i = 0; i < 3; i++) {Topic topic = {.name = "temperature",.data = &temp_data[i],.data_size = sizeof(float),.timestamp = (uint32_t)time(NULL)};publish(sensor_publisher, &topic);}// 取消訂閱unsubscribe(sensor_publisher, "系統日志");// 再次發布數據float final_temp = 35.2f;Topic topic = {.name = "temperature",.data = &final_temp,.data_size = sizeof(float),.timestamp = (uint32_t)time(NULL)};publish(sensor_publisher, &topic);// 清理資源destroy_publisher(sensor_publisher);return 0;
}

5. 代碼分析

5.1 關鍵設計點

  1. 發布者管理訂閱者列表
  2. 回調機制實現通知
  3. 主題數據封裝
  4. 動態訂閱管理

5.2 實現特點

  1. 函數指針實現回調
  2. 支持用戶數據傳遞
  3. 訂閱者管理完善
  4. 資源管理安全

6. 編譯和運行

gcc -c pubsub.c -o pubsub.o
gcc -c main.c -o main.o
gcc pubsub.o main.o -o pubsub_demo

7. 注意事項

  1. 訂閱者數量限制
  2. 內存管理安全
  3. 回調函數異常處理
  4. 線程安全考慮

8. 改進建議

  1. 添加主題過濾
  2. 實現異步通知
  3. 支持優先級訂閱
  4. 添加訂閱者分組

9. 總結

發布訂閱模式通過解耦發布者和訂閱者,實現了靈活的消息通知機制。這種模式特別適合處理事件驅動的場景。

參考資料

  1. 《設計模式:可復用面向對象軟件的基礎》
  2. 《C語言程序設計》
  3. 《事件驅動編程》

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/73124.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73124.shtml
英文地址,請注明出處:http://en.pswp.cn/web/73124.shtml

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

相關文章

藍橋杯2023年第十四屆省賽真題-異或和之差

題目來自DOTCPP&#xff1a; 思路&#xff1a; 什么是異或和&#xff1f; ①題目要求我們選擇兩個不相交的子段&#xff0c;我們可以枚舉一個分界線i&#xff0c;子段1在 i 的左邊&#xff0c; 子段2在 i 的右邊&#xff0c;分別找到子段1和子段2的最大值、最小值。 ②怎么確…

Linux作業2——有關文件系統權限的練習

1、創建/www目錄&#xff0c;在/www目錄下新建name和https目錄&#xff0c;在name和https目錄下分別創建一個index.html文件&#xff0c;name下面的index.html文件中包含當前主機的主機名&#xff0c;https目錄下的index.html文件中包含當前主機的ip地址。 #創建/www目錄&…

leeCode 70. 爬樓梯

假設你正在爬樓梯。需要 n 階你才能到達樓頂。 每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢&#xff1f; 示例 1&#xff1a; 輸入&#xff1a;n 2 輸出&#xff1a;2 解釋&#xff1a;有兩種方法可以爬到樓頂。 1. 1 階 1 階 2. 2 階 示例 2&#x…

算法題(105):小貓爬山

審題&#xff1a; 本題需要我們找出將n個小貓放在有限重的纜車上運下山所需的最小纜車數 時間復雜度分析&#xff1a;本題的數據量小于等于18&#xff0c;所以我們在做好剪枝的前提下可以使用深度優先搜索解題 思路&#xff1a; 方法一&#xff1a;dfs 搜索策略&#xff1a;將小…

第十六章:Specialization and Overloading_《C++ Templates》notes

Specialization and Overloading 一、模板特化與重載的核心概念二、代碼實戰與測試用例三、關鍵知識點總結四、進階技巧五、實踐建議多選題設計題代碼測試說明 一、模板特化與重載的核心概念 函數模板重載 (Function Template Overloading) // 基礎模板 template<typename…

多協議兼容+高并發處理:EasyCVR如何破解AI安防規模化落地難題?

隨著AI技術在安防領域的深入應用&#xff0c;規模化部署面臨兩大核心挑戰&#xff1a;設備協議碎片化導致的接入壁壘與海量視頻流并發帶來的性能瓶頸。TSINGSEE青犀視頻的EasyCVR平臺通過“多協議兼容高并發處理”雙引擎驅動&#xff0c;結合云邊端協同架構與智能算法優化&…

IntelliJ IDEA 中 Git 高頻問題與操作詳解|新手避坑指南

標簽&#xff1a;IntelliJ IDEA Git操作, Git教程, 版本控制, 沖突解決, 分支管理 引言 你是否遇到過這些問題&#xff1f; 代碼提交后想撤銷怎么辦&#xff1f;合并分支時沖突不會解決&#xff1f;不小心把錯誤代碼推送到遠程倉庫&#xff1f; 本文針對 IntelliJ IDEA 中 Git …

【聊聊層次式架構設計:像搭樂高一樣構建軟件大廈】

文章目錄 聊聊層次式架構設計&#xff1a;像搭樂高一樣構建軟件大廈理論篇&#xff1a;層次式架構的“千層套路”最底層&#xff1a;基礎設施層——默默付出的“基石俠”數據訪問層&#xff1a;“數據快遞員”業務邏輯層&#xff1a;智慧的“大腦中樞”表示層&#xff1a;軟件的…

N列股票收盤價為起點的馬科維茨(Markowitz)均值—方差理論

1. 數據準備與收益率計算 輸入數據&#xff1a; 假設你有一個矩陣&#xff0c;每一列代表一只股票的歷史收盤價序列。每一行對應一個時間點的收盤價。 計算收益率&#xff1a; 馬科維茨理論要求使用資產的收益率而非價格。常用的收益率計算方法有對數收益率或簡單收益率。 2.…

Conda常用命令匯總(持續更新中)

原文章&#xff1a;安裝和使用Miniconda來管理Python環境-CSDN博客 一、Miniconda的使用 Miniconda沒有GUI界面&#xff0c;只能通過conda命令對Python環境和軟件包進行管理&#xff0c;所以這里主要介紹一下conda的常用命令。 1. Conda相關 (1)查詢conda版本 conda --vers…

Redis Cluster 詳解

Redis Cluster 詳解 1. 為什么需要 Redis Cluster&#xff1f; Redis 作為一個高性能的內存數據庫&#xff0c;在單機模式下可能會遇到以下問題&#xff1a; 單機容量受限&#xff1a;Redis 是基于內存存儲的&#xff0c;單機的內存資源有限&#xff0c;單實例的 Redis 只能…

利用 MATLAB/Simulink 建立完整的控制系統模型,并進行階躍響應和負載擾動響應仿真

-利用 MATLAB/Simulink 建立完整的控制系統模型,包括單一控制回路(電流、速度、位置)和整個系統的級聯模型 仿真任務包括驗證各回路的階躍響應、負載擾動響應等,確保系統在動態性能上滿足設計要求。 以下是在MATLAB/Simulink中建立完整控制系統模型(包含單一控制回路和級聯…

python基于spark的心臟病患分類及可視化(源碼+lw+部署文檔+講解),源碼可白嫖!

摘要 時代在飛速進步&#xff0c;每個行業都在努力發展現在先進技術&#xff0c;通過這些先進的技術來提高自己的水平和優勢&#xff0c;汽車數據分析平臺當然不能排除在外。本次我所開發的心臟病患分類及可視化系統是在實際應用和軟件工程的開發原理之上&#xff0c;運用Pyth…

3.milvus索引-HNSW

索引作用 加速大型數據集上的查詢。 向量字段&#xff0c;僅只能創建一個索引。 milvus支持的向量索引類型大部分使用 近似最近鄰搜索算法。ANNS該算法的核心不局限于返回最準確的結果&#xff0c;而是僅搜索目標的鄰居。ANNS通過在可接受的范圍內犧牲準確性提高檢索效率。 …

Python(學習二)

列表&#xff1a;[] 列表是可以容納不同類型的數據的 列表取&#xff1a; 列表切片&#xff1a;一次去獲取多個元素 第三個參數&#xff0c;設置跨度值&#xff1a; 列表倒序輸出 列表增&#xff1a; 列表后面添加元素&#xff1a; 切片&#xff1a;實現添加元素 任意位置…

【中文翻譯】第1章-The Algorithmic Foundations of Differential Privacy

為方便閱讀&#xff0c;故將《The Algorithmic Foundations of Differential Privacy》翻譯項目內容搬運至此&#xff1b; 教材原文地址&#xff1a;https://www.cis.upenn.edu/~aaroth/Papers/privacybook.pdf 中文翻譯版 Github 項目地址1&#xff1a;https://github.com/gu…

UI-TARS與Midscene.js自動化探索

結合 Midscene.js 和 UI-TARS 大模型 實現 UI 頁面自動化的可實施方案&#xff0c;涵蓋環境配置、核心流程、代碼示例及優化建議&#xff1a; 一、環境配置與工具集成 安裝 Midscene.js 方式一&#xff1a;通過 Chrome 插件快速安裝&#xff08;適用于瀏覽器自動化場景&#x…

Web開發-JS應用NodeJS原型鏈污染文件系統Express模塊數據庫通訊

知識點&#xff1a; 1、安全開發-NodeJS-開發環境&功能實現 2、安全開發-NodeJS-安全漏洞&案例分析 3、安全開發-NodeJS-特有漏洞 node.js就是專門運行javascript的一個應用程序&#xff0c;區別于以往用瀏覽器解析原生js代碼&#xff0c;node.js本身就可以解析執行js代…

Spring AOP 核心概念與實踐指南

第一章&#xff1a;AOP 核心概念與基礎應用 1.1 AOP 核心思想 ?面向切面編程&#xff1a;通過橫向抽取機制解決代碼重復問題&#xff08;如日志、事務、安全等&#xff09;?核心優勢&#xff1a;不修改源代碼增強功能&#xff0c;提高代碼復用性和可維護性 1.2 基礎環境搭…

Flutter使用自簽證書打包ipa

在 Flutter 中使用自簽證書打包 IPA 文件&#xff0c;可以通過以下步驟完成&#xff1a; 1. 準備自簽證書 方式一 生成自簽證書&#xff1a; 打開 鑰匙串訪問 應用。選擇 證書助理 > 創建證書。按照提示填寫證書信息&#xff0c;選擇證書類型為 代碼簽名&#xff0c;并保存…