[C++11 併發程式設計] 15 承諾promise
阿新 • • 發佈:2019-02-02
假設有一個應用程式應用程式用於處理大量的網路連線,通常我們會為每一個連線建立單獨的處理執行緒。當執行緒數量較少時,這樣是可行的,但是隨著連線數量的增加,大量的執行緒需要消耗大量的系統資源。這樣,使用較少的執行緒,每個執行緒處理多個連線更為合適。
std::promise<T>提供了一個設定值的機制(型別T),通過與之關聯的期望物件可以獲取到被設定的值。std::promise/std::future一起配合,等待執行緒可以阻塞在期望上,實現承諾的執行緒可以使用promise物件來設定值,使得期望被滿足。
如下是一個使用promise的簡單示例,主執行緒建立一個promise,將於promise關聯的期望交給新的執行緒th1。新執行緒等待從期望獲取資料,主執行緒通過promise向期望設定值。
// promise example #include <iostream> // std::cout #include <functional> // std::ref #include <thread> // std::thread #include <future> // std::promise, std::future void print_int (std::future<int>& fut) { int x = fut.get(); std::cout << "value: " << x << '\n'; } int main () { std::promise<int> prom; // 建立承諾 std::future<int> fut = prom.get_future(); // 獲取期望 std::thread th1 (print_int, std::ref(fut)); // 將期望交給一個新的執行緒 prom.set_value (10); // 履行承諾 // 與對期望的get()操作同步 th1.join(); return 0; }
程式執行結果如下:
value: 10
另一個例子則是處理多個網路連結,使用std::promise<bool>/std::future<bool>對來標示成功傳送了一塊資料。於期望關聯的是一個表示成功或失敗的標誌。對於接收到的網路包,與期望關聯的則是收到的資料。
到現在為止,我們看到的程式碼都忽略了異常。有些時候,由於磁碟滿了,資料沒找到,網路問題都有可能在某個執行緒執行操作時,導致函式呼叫直接返回帶有異常的錯誤,C++標準庫提供了一個機制在這些情況下處理異常,可以將異常存放在相關結果中返回給等待結果的執行緒。下一節,我們將看到如何通過期望來傳遞異常。#include <future> void process_connections(connection_set& connections) { // 迴圈直到done()返回true while(!done(connections)) { // 迴圈檢查每一個連線 for(connection_iterator connection=connections.begin(),end=connections.end(); connection!=end; ++connection) { // 如果有輸入資料 if(connection->has_incoming_data()) { data_packet data=connection->incoming(); // 通過資料的id獲得對應的promise std::promise<payload_type>& p= connection->get_promise(data.id); // 將資料設定給promise p.set_value(data.payload); } // 如果有輸出資料 if(connection->has_outgoing_data()) { outgoing_packet data= connection->top_of_outgoing_queue(); connection->send(data.payload); // 從輸出佇列中獲取資料並通過連線進行傳送 // 傳送完畢則設定promise的值為true以表明傳送成功 data.promise.set_value(true); } } } }