首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 異步調用核心:future/promise 實現原理深度剖析

     編輯:關於C++

前言

異步編程中,回調地獄讓代碼難以維護。C++11/Boost 引入 future/promise 機制,將異步操作轉為同步風格,代碼清晰、易組合。本文從組件依賴、核心類設計、共享狀態機制、then 鏈式調用實現、when_all 並行併發五個維度,深度剖析基於 Boost 實現的 future/promise 內部原理,附關鍵源碼邏輯解讀。

一、核心組件依賴圖

+------------------+
|  bind / function |  (回調綁定與類型擦除)
+------------------+
| shared_ptr /     |  (引用計數 / 作用域指針 / 元組 / 異常)
| scoped_ptr       |
| tuple            |
| exception        |
+------------------+
| Future / Promise |  (核心異步原語)
+------------------+
|   when_all       |  (並行任務聚合)
+------------------+

二、關鍵基礎設施

1. enable_shared_from_this 模式

當對象由 shared_ptr 管理,且成員函數需將 指向自身的 shared_ptr 傳遞給外部時,必須繼承 enable_shared_from_this 並調用 shared_from_this()。

class TcpConnection : public enable_shared_from_this {
    void start() {
        async_write(socket_, buffer_, 
            bind(&TcpConnection::handle_write, shared_from_this(), _1, _2));
        // 若傳 this,外部構造 shared_ptr 會導致雙重析構!
    }
};

原因:直接傳 this 構造 shared_ptr 會創建**獨立控制塊**,導致雙重刪除。shared_from_this() 返回與原 shared_ptr 共享控制塊的新 shared_ptr。

2. tuple 多返回值

匿名聚合多個值,避免定義專用 struct,std::pair 是 2 元組特例。

三、Future / Promise 核心架構

1. 類關係圖

FutureBase (非特化通用邏輯)
    ↑
Future (具體接口:get/then/isDone...)

Promise (提供 setValue/setException)
    │
    └─ m_future → SharedPtr> ←──┐
                                                         │ 共享同一個
Future                                                │ FutureObject
    │                                                    │
    └─ m_future ────────────────────────────────────────┘

2. 共享狀態 FutureObjectInterface 兩種實現

實現類適用場景特點
FutureObject與 Promise 配對(異步產生值)**線程安全**:內部鎖保護,支援多線程 set/get、回調註冊、狀態變更通知
PromptFutureObject直接用值構造 Future(如 makeFuture)**無鎖只讀**:值構造時已就緒,無併發寫入,性能更優

3. Promise 接口


setValue(T)           // 設置值(僅能調用一次,否則拋異常)
setException(E)       // 設置異常
getFuture()           // 返回綁定同一共享狀態的 Future

4. Future 接口


get()                 // 阻塞等待就緒,返回值或拋異常
isDone() / hasValue() / hasException()
then(callback)        // 註冊回調,返回新 Future(鏈式調用核心)

四、then 鏈式調用機制深度解析

1. 簽名與返回類型推導


template
Future::type> 
then(const Callback&)>& callback);
  • resolved_type 特化:
    resolved_type::type = T
    resolved_type>::type = U
    ⇒ 無論回調返回 U 還是 Future,then 統一返回 Future,保證鏈式調用類型一致。

2. 核心實現邏輯


Future then(Callback) {
    // 1. 檢查 m_future 已初始化
    // 2. 創建新 Promise promise;  // 承載回調返回值
    // 3. 將 callback 包裝為 SequentialCallback
    //    SequentialCallback 持有:原 callback + 新 promise
    // 4. 註冊到共享狀態:m_future->registerCallback(wrapped)
    // 5. 返回 promise.getFuture()
}

3. SequentialCallback 三種運行模式

回調返回類型處理邏輯
void調用 callback,調用 promise.set()(無值)
非 Future 值 U調用 callback 得 u,調用 promise.setValue(u)
Future調用 callback 得 fut,對 fut 再次 then 綁定 ForwardValue,最終將值轉發給外層 promise

關鍵點:回調返回 Future 時,通過**遞歸 then + ForwardValue** 將內層值「剝離」傳遞給外層 promise,實現扁平化鏈式調用。

4. 類型萃取技術

利用 enable_if + is_void + is_future_type (traits) 在編譯期分發三種 run 重載,零運行時開銷。

五、when_all 並行聚合(草案)


// 目標:同時啟動多個異步任務,全部完成後聚合結果
Future> when_all(Future f1, Future f2, ...);

// 實現思路:
// 1. 創建一個共享計數器(原子計數 / 條件變量)
// 2. 對每個 fi 註冊回調:完成時計數器--,存儲結果到 tuple 對應位置
// 3. 當計數器歸零 → 觸發聚合 Future 就緒
// 4. 利用 tuple 存儲異構結果,類型安全

完整實現涉及 tuple 索引序列、原子操作、條件變量通知,篇幅限制此處略過,後續補充。

六、使用示例:串行異步調用鏈


// 業務:A → B(異步) → C(異步) → 返回客戶端
Future f = sendBReq(prxB, input);          // 發起 B 請求,得 future
f.then(bind(&handleB, prxC))                       // B 回包後處理,發起 C 請求
 .then(bind(&handleC, current));                   // C 回包後最終回包客戶端

// sendBReq 內部:
Promise promise;
callback = new BCallback(current, promise); // 持有 promise
prxB->async_call(callback, input);
return promise.getFuture(); // 返回綁定同一 shared state 的 future

// handleB 簽名:Future handleB(PrxC prx, const Future& f)
// 內部:f.get() 取 B 結果 → sendCReq → 返回 C 的 future
// then 機制自動將 C 的 future 扁平化傳遞給下一層

七、總結:核心設計精髓

  1. 共享狀態分離:Future(讀端)與 Promise(寫端)通過 shared_ptr 共享狀態,解耦生產者/消費者生命週期。
  2. 兩種 FutureObject:FutureObject(異步、需鎖)vs PromptFutureObject(即時值、無鎖),場景化優化。
  3. then 扁平化:SequentialCallback + ForwardValue 遞歸剝離嵌套 Future,保證鏈式調用類型穩定。
  4. 類型擦除 + Traits:Callback 擦除具體函數類型,resolved_type 編譯期萃取返回值類型,實現泛型鏈式調用。
  5. 線程安全由共享狀態保證:鎖保護 setValue/registerCallback/doPendingCallbacks,調用者無需額外同步。

掌握這些原理,不僅能正確使用 future/promise,更能在需要時擴展自定義異步組件(如帶超時的 future、可取消的 promise 等)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved