Boost.Asio 在 Hwmon Sensor 服務中的非同步框架與狀態協調

更新 發佈閱讀 14 分鐘

Ciao~ 各位 OpenBMC 的戰友們,不知道你有沒有跟我一樣的經驗:在任何一個 service 的實作中,你總會看到 Boost.Asio 像空氣一樣無所不在。雖然原作者們早已經把架構搭得穩穩妥妥,該有的 class 也設計得服服貼貼,我們身為『後人』,幾乎只需要動動小手術——新增或微調 member function 就好。然而,當我們對一個頻繁相遇的基礎設施一無所知時,帶我進入這一行的老闆常說:「你不知道他怎麼好的?有一天他怎麼死的你就也會告訴我你不知道...」。To be honest, I've actually said that... I really didn't know! 囧!

首先:Boost.Asio 是什麼?

Boost.Asio 是一個提供非同步 I/O 支援的 C++ 函式庫,核心是 io_context(或舊稱 io_service),用來管理事件(event)的排程與執行。

其核心運作如下:

boost::asio::io_context io;
io.run(); // 進入事件循環

io_context 內部維護一個 事件佇列(event queue),當有任務、計時器、或 I/O 完成事件加入時,loop 會逐一取出並執行 callback handler。

為什麼我們需要「非同步」?

如果前面這段介紹看完,你心中對於這個問題已經有答案,表示你的基礎打得很不錯。相信也有很多人一頭霧水,覺得同步vs非同步有很重要嗎?差別是什麼?還沒有很明白。接著我用說故事的方式,不專業的講一下我對於這件事情的理解。想像一下,你開了一家餐廳,你是櫃檯的老闆,你的工作是接待客人、點菜、收錢。你可能會有兩種經營的模式:

同步(Synchronous / Blocking)—— 一次只能做一件事
在這家「同步餐廳」裡,服務流程是這樣的:

  1. 客人 A 點了一份「宮保雞丁」(I/O 任務)。 (我自從從國外回來好愛吃宮保雞丁,笑死!)
  2. 老闆(主程式):「好的,請稍候。」
  3. 老闆走進廚房,開始盯著廚師把宮保雞丁炒完(等待 I/O 完成)。
  4. 期間,門外排了長長的隊伍,客人 B、C、D... 都卡住了
    (他們都不能點餐, 一直在排隊,好幾次在歐洲吃飯都這個狀態,
    我都想說是沒有服務人員了嗎?)
  5. 宮保雞丁終於上桌,老闆走回櫃檯。
  6. 老闆:「下一位。」(我如果是下一位,我已經去下一家了)

【技術解析】:在程式世界裡,這叫做 Blocking I/O (阻塞式 I/O)。當你的主程式發出一個耗時的請求(例如:發送網路封包、讀取感測器),它會停下來,等待 I/O 操作完成並返回結果,期間完全不能處理其他任務。

非同步(Asynchronous / Non-blocking)—— 做完就通知我

在這家「非同步餐廳」(也就是 Boost.Asio 採用的模式)裡,流程煥然一新:

  1. 客人 A 點了一份「宮保雞丁」(I/O 任務)。
  2. 老闆(主程式):「好的,點菜單給廚房。下一位。」
  3. 老闆繼續接待客人 B、C、D,收錢、倒水、處理投訴(處理其他任務)。
  4. 廚房(作業系統/硬體)炒完菜後,搖鈴通知老闆:「A 客人的宮保雞丁好了!」
  5. 老闆聽到鈴響,把菜端給客人 A。

【技術解析】:這就是 Non-Blocking I/O (非阻塞式 I/O)。主程式發出 I/O 請求後,立刻返回,可以繼續執行其他程式碼(例如處理 D-Bus 請求、處理定時器)。當 I/O 任務(例如網路連線、感測器讀取)完成時,系統會發出一個「完成通知」給主程式。

從 Hwmon Sensor Monitoring 來看看 Boost.Asio 的角色

Sensor Monitoring是BMC中很重要的功能之一,如果你有打開過"dbus-sensors"這個Repo就會看到有很多不同的services專門為不同種類的sensor在不斷回報著主機板的溫度、電壓、風扇轉速與電源狀態,讓 BMC 能在任何時刻掌握機器的健康狀況。讀取sensor這件事情其實並不簡單,首先,要先建立每個sensor的基本資訊,這些資訊包含大家熟知的sensor name, sensor number, threshold value, hysteresis...etc. 同時要留意兩件很重要的事情,一是presence的狀態,因為現在很多系統都是設計某些板子或小卡可以熱插拔,如果卡拔走sensor也就不在了。二是Power的狀態,如果sensor所在的位置供電狀態為power off,無法對他進行讀值也是非常合理的了,就怕這時候你誤判他為sensor failure。那最後就是....對!你要可以判斷何為sensor failure? 這對data center很重要,只有知道真正的錯誤才有辦法解決問題。

每支sensor monitoring service都大同小異,我們就來看一下Hwmon這裡的main function都做了些什麼?首先,會先看到環境設定相關的部分:boost::asio::io_context 是事件中樞(event loop),所有任務——不論是 D-Bus signal、I/O 操作或 timer——都要透過它排隊執行。systemBus 負責與 D-Bus 互動,而 objectServer 則提供一個「在 BMC 上註冊出來的服務名稱」。從這裡開始,BMC 就有了一個在 D-Bus 上能被尋址的 sensor 伺服器。(看到這邊如果對於dbus還不是非常了解的朋友,可以先去看我先前寫的Dbus的內容。)這種設計的關鍵在於,整個程式在 io.run() 被呼叫之前,其實什麼都還沒開始做。所有的callback、非同步監聽與初始化任務,都只是被「註冊」到 io_context 的內部。等到 io.run() 啟動後,Boost.Asio 才會進入一個永不結束的事件循環,持續處理當前佇列中的任務,並隨時準備響應和執行在服務運行期間由硬體或作業系統「推入」的非同步 I/O 完成事件。 這些事件可能是sensor reading發生變化,系統configuration發生變化,或者是power satus發生變化...etc.

Sensor Polling: 讀值發生改變

createSensors() 被呼叫時,程式會為每個 sensor 建立一個物件。每個物件都會在建構時啟動一個屬於自己的 timer,週期性地觸發讀值:

void HwmonTempSensor::setupRead()
{

if (!readingStateGood())
{

markAvailable(false);
updateValue(std::numeric_limits<double>::quiet_NaN());
restartRead();
return;
}

std::weak_ptr<HwmonTempSensor> weakRef = weak_from_this();
inputDev.async_read_some_at(
0, boost::asio::buffer(readBuf),
[weakRef](const boost::system::error_code& ec, std::size_t bytesRead) {
std::shared_ptr<HwmonTempSensor> self = weakRef.lock();
if (self)
{
self->handleResponse(ec, bytesRead);
}
});
}

這段設計的精髓在於——整個 polling 運作於同一個 event loop 裡,而不是每個 sensor 各開一個 thread。async_wait 並不會阻塞程式,它只會向 io_context 登記「一秒後請執行這個 callback」。等到時間到時,Boost.Asio 會在事件佇列中排程這個任務,讀取溫度檔案、更新 D-Bus 屬性,然後再次呼叫 restartRead() 自我排程下一輪。

Configuration 變化與防抖動的策略

關鍵程式如下:

std::function<void(sdbusplus::message_t&)> eventHandler = [&](auto& message) {
sensorsChanged->insert(message.get_path());
filterTimer.expires_after(1s);
filterTimer.async_wait([&](const boost::system::error_code& ec) {
if (ec == boost::asio::error::operation_aborted) return;
createSensors(io, objectServer, sensors, systemBus, sensorsChanged, false);
});
};
setupPropertiesChangedMatches(*systemBus, sensorTypes, eventHandler);

這裡的 eventHandler 是用來監聽 PropertiesChanged 訊號——當 Entity-Manager 偵測到新的卡被插入或拔除時,它會在 D-Bus 上發出這個 signal。

有趣的是,這段程式不是立刻重建 sensor,而是先用一個 filterTimer 延遲一秒。這樣設計的原因在於「防抖動(debounce)」:在 power stress 或熱插拔測試中,Configuration 可能在短時間內連續變動數次,如果每次都立刻呼叫 createSensors(),整個系統會陷入大量重建、刪除、再重建的循環。來看看filterTimer 的用法:

  • 當有新的事件進來時,就重設 timer。
  • 若在 1 秒內沒有新的事件,就執行重建。
  • 若 timer 被重設,前一個 async_wait callback 會收到 operation_aborted,自動終止。

這讓程式能夠在事件風暴中維持穩定,不會頻繁地消耗系統資源。

電源狀態發生變化的處理

接著我們看到這段程式:

auto powerCallBack = [&sensors, &io, &objectServer, &systemBus]
(PowerState type, bool state) {
powerStateChanged(type, state, sensors, io, objectServer, systemBus);
};
setupPowerMatchCallback(systemBus, powerCallBack);

這裡註冊了一個電源狀態的 callback。當Power State Manager(負責觀察power change的service) 發出「上電」或「掉電」訊號時,這個callback就會被觸發。在這個時刻,Boost.Asio 發揮的作用是事件排程的中介者。它確保這個回呼會被安全地、同步地加入 io_context 的事件佇列,而不會和正在執行的 sensor polling 發生衝突。若系統掉電,callback 會呼叫 timer.cancel() 停止所有 sensor 的讀值排程;若重新上電,則會重新建立 sensor 物件並啟動新的 timer。

如果看到這邊,你的心中有浮現出一個時間差會導致sensor failure發生的corner case,這邊我先不細談,有興趣的朋友可以了解一下另外兩個機制:

  1. Sensor::updateValue() 會再查一次 readingStateGood()
  2. Sensor::incrementError() 也先檢查 readingStateGood()

結語

如果要用一句話來總結 Boost.Asio 在這裡的角色,那就是:

它讓整個 sensor-monitor 變成一個「有節奏、可預測、可恢復」的系統。

Boost.Asio 提供的 io_context 不只是個事件容器,而是一套完整的非同步執行框架。它負責處理所有 timer、callback、signal,確保它們不會彼此衝突。這種架構讓 OpenBMC 的程式在單執行緒下依然能具備非同步的彈性,並自然地融合 D-Bus 事件、I/O 操作與時間驅動邏輯。

在沒有 Asio 的情況下,我們可能需要手動管理多執行緒、mutex、條件變數、sleep 等複雜結構。Boost.Asio 把這些煩瑣的底層同步細節抽象化成事件驅動模型,讓韌體工程師能專注於「邏輯」。








留言
avatar-img
L'Angolo di Embedded
25會員
26內容數
這裡會有一些我對於OpenBMC, Embedded Software的學習與經驗分享, 本來只在Line社群跟大家互動, 但是有夥伴提出想要看到歷史文章的需求, 於是我決定把它放到這裡, 努力磨練自己的技術和文筆。
L'Angolo di Embedded 的其他內容
2025/10/06
本文說明檔案描述子(File Descriptor, FD)的概念,以及Buffered I/O與System Call的差異。透過介紹open()函式的Flags與Mode參數,並利用strace工具觀察程式與核心的互動,幫助開發者理解底層運作機制。
2025/10/06
本文說明檔案描述子(File Descriptor, FD)的概念,以及Buffered I/O與System Call的差異。透過介紹open()函式的Flags與Mode參數,並利用strace工具觀察程式與核心的互動,幫助開發者理解底層運作機制。
2025/09/29
本文旨在深入剖析 Linux 檔案系統的核心概念,包括「萬物皆檔案」的哲學、檔案路徑、存取機制、inode 運作原理、連結機制、特殊檔案以及 OpenBMC 特有的檔案系統架構。透過理解這些基礎知識,開發者能更有效地在嵌入式系統中與硬體互動,並掌握 OpenBMC 的檔案系統設計。
2025/09/29
本文旨在深入剖析 Linux 檔案系統的核心概念,包括「萬物皆檔案」的哲學、檔案路徑、存取機制、inode 運作原理、連結機制、特殊檔案以及 OpenBMC 特有的檔案系統架構。透過理解這些基礎知識,開發者能更有效地在嵌入式系統中與硬體互動,並掌握 OpenBMC 的檔案系統設計。
2025/09/22
一起探討嵌入式系統開發中至關重要的建置系統與GNU工具鏈,涵蓋預處理、編譯、組譯、連結、定位與載入等步驟,並比較原生編譯與交叉編譯,最後介紹Make和Meson建置系統,以及提升嵌入式程式碼開發效率的技巧。
2025/09/22
一起探討嵌入式系統開發中至關重要的建置系統與GNU工具鏈,涵蓋預處理、編譯、組譯、連結、定位與載入等步驟,並比較原生編譯與交叉編譯,最後介紹Make和Meson建置系統,以及提升嵌入式程式碼開發效率的技巧。
看更多
你可能也想看
Thumbnail
B一樣都是提供 數據服務 雲端服務 AI服務 資安服務 的公司, 該如何提升自家的競爭力? 使優質的客戶會主動找我們服務? 幸福課程 幸福教練黃老師 潮資訊媒體 社群編輯 數據服務、雲端服務、AI服務、資安服務 是四個密不可分的領域, 彼此之間有著緊密的聯繫。 因此,要提
Thumbnail
B一樣都是提供 數據服務 雲端服務 AI服務 資安服務 的公司, 該如何提升自家的競爭力? 使優質的客戶會主動找我們服務? 幸福課程 幸福教練黃老師 潮資訊媒體 社群編輯 數據服務、雲端服務、AI服務、資安服務 是四個密不可分的領域, 彼此之間有著緊密的聯繫。 因此,要提
Thumbnail
核心元件 Spring Boot:Spring Cloud的基礎框架。 Spring Cloud Starters:Spring Boot的依賴管理。 Consul:微服務系統的註冊中心。 Eureka:微服務系統的註冊中心。 Feign:簡化微服務之間的溝通方式。 Ribbon:處理程
Thumbnail
核心元件 Spring Boot:Spring Cloud的基礎框架。 Spring Cloud Starters:Spring Boot的依賴管理。 Consul:微服務系統的註冊中心。 Eureka:微服務系統的註冊中心。 Feign:簡化微服務之間的溝通方式。 Ribbon:處理程
Thumbnail
業務流程自動化 (BPA, Business Process Automation) 是一種利用技術工具和系統,來自動執行、監控和管理企業流程的方法。企業需要以更少的資源做更多的事,來確保流程達到高效率的目的。許多企業開始建置業務流程自動化作業,解決工作流程中的獨特問題,將生產力最大化。
Thumbnail
業務流程自動化 (BPA, Business Process Automation) 是一種利用技術工具和系統,來自動執行、監控和管理企業流程的方法。企業需要以更少的資源做更多的事,來確保流程達到高效率的目的。許多企業開始建置業務流程自動化作業,解決工作流程中的獨特問題,將生產力最大化。
Thumbnail
Gorm是一款性能極好的ORM,且友善,因此可以明顯的提高開發效率。 特點 全功能ORM 支持連結 支援Hook 支持預先載入 支援交易 支持復合主鍵 支持SQL生成器 支援資料庫自動遷移 支援自訂日誌 可擴充性 所有功能都被測試覆蓋 安裝 go get -u gor
Thumbnail
Gorm是一款性能極好的ORM,且友善,因此可以明顯的提高開發效率。 特點 全功能ORM 支持連結 支援Hook 支持預先載入 支援交易 支持復合主鍵 支持SQL生成器 支援資料庫自動遷移 支援自訂日誌 可擴充性 所有功能都被測試覆蓋 安裝 go get -u gor
Thumbnail
支援Go所有的類型儲存,且可以用原生SQL敘述與跨資料庫查詢。 映射關係 table->struct record->object field->attribute 安裝 go get github.com/astaxie/beego/orm​ go get github.com
Thumbnail
支援Go所有的類型儲存,且可以用原生SQL敘述與跨資料庫查詢。 映射關係 table->struct record->object field->attribute 安裝 go get github.com/astaxie/beego/orm​ go get github.com
Thumbnail
Function的使用方式
Thumbnail
Function的使用方式
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
本篇介紹跨平台存取控制系統 Oso 以及它的規則語言 Polar,用他們替專案建立 RBAC 以及資源級的存取控制。
Thumbnail
本篇介紹跨平台存取控制系統 Oso 以及它的規則語言 Polar,用他們替專案建立 RBAC 以及資源級的存取控制。
Thumbnail
在網路速度有限的情況下,依序記錄不斷產生的資訊,能統計使用者在頁面上操作了哪些功能。
Thumbnail
在網路速度有限的情況下,依序記錄不斷產生的資訊,能統計使用者在頁面上操作了哪些功能。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News