文章目錄
- future前言
- future描述
- future類成員使用
- 總結
future前言
首先檢視如下代碼
#include <iostream>
#include <thread>
#include <future>
#include <mutex>
using namespace std;
void fun1(int n,int &x) {
int res = 1;
for (int i = n; i>1; --i) {
res *=i;
}
cout << "Result is " << res << endl;//輸出最終的結果并指派給共享變量x
x = res;
}
int main()
{
int x;
std::thread t1(fun1,4,std::ref(x));
t1.join();
return 0;
}
這段代碼僅擁有一個線程,但是可以很明顯得看到主線程和t1線程想要共享同一個變量x,同時x是需要在t1線程進行指派将結果傳回給主線程,由主線程來擷取。這樣的線程之間的變量傳遞,我們所知道的傳遞方式隻能是傳遞引用。同時僅僅傳遞引用是不夠的,因為線程之間的變量共享需要對變量進行保護才能安全有效共享,這樣就需要引入
mutex
互斥變量和
condition_variable
條件變量對共享變量進行保護。
這樣會導緻代碼邏輯更加複雜,邏輯細節也會變得非常謹慎。這個時候我們引入
future
類對以上操作進行簡化。
future描述
- 頭檔案
<future>
- 聲明
template< class T > class future<T&>;
-
簡介
類模版提供了一種異步通路操作機制如下:future
- 異步操作能提供一個 std::future 對象給該異步操作的建立者。其中包括
、 std::async
或 std::packaged_task
的傳回值為std::promise
對象std::future
- 異步操作的建立者能用各種方法查詢、等待或從 std::future 提取值。若異步操作仍未提供值,則這些方法可能阻塞。如使用
建立的異步操作傳回的std::async
對象未擷取值,那麼future
将不會退出std::async
- 異步操作準備好發送結果給建立者時,它能通過修改連結到建立者的
的共享狀态(例如std::future
)進行std::promise::set_value
future類成員使用
-
std::future<T>::get
擷取異步操作的傳回結果
get 方法等待直至 future 擁有合法結果并(依賴于使用哪個模闆)擷取它。它等效地調用 wait() 等待結果
這裡需要簡單說明下get函數的傳回值,它的傳回值為
類型,即将之前的傳回結果包括值和位址都進行指派。如果二次嘗試std::move()
,回通路到空的值和位址,報出異常get
std::future_error
。
我們對剛開始的代碼更改如下:
#include <iostream>
#include <thread>
#include <future>
#include <mutex>
using namespace std;
int fun1(int n) {
int res = 1;
for (int i = n; i>1; --i) {
res *=i;
}
cout << "Result is " << res << endl;
return res;
}
int main()
{
int x;
//std::thread t1(fun1,4,std::ref(x));
//t1.join();
//我們使用異步操作,并使用get函數擷取異步操作函數的合法傳回值
std::future<int> fu = std::async(fun1,4);
x = fu.get();
return 0;
}
如上代碼,我們使用
std::async()
異步操作來建立字線程,并傳回一個future類的對象,然後由
future
對象的
get()
函數來擷取子線程合法的傳回結果。
關于
async()
等異步操作将會在下一篇進行分享,這裡簡單描述一下:
async
提供的是從子線程擷取數值到主線程,如果我們想要從主線程擷取數值到子線程,則需要
promise
異步操作
檢視如下代碼為我們利用
promise
從主線程擷取數值到子線程
#include <iostream>
#include <thread>
#include <future>
#include <mutex>
using namespace std;
int fun1(std::future<int> &f) {
int res = 1;
int n = f.get();
for (int i = n; i>1; --i) {
res *=i;
}
cout << "Result is " << res << endl;
return res;
}
int main()
{
int x;
//std::thread t1(fun1,4,std::ref(x));
//t1.join();
std::promise<int> p;
//标示f是一個需要從未來擷取數值future對象
std::future<int> f = p.get_future();
std::future<int> fu = std::async(std::launch::async,fun1, std::ref(f));
//為f設定數值,在子線程中進行f.get()擷取主線程到數值
p.set_value(4);
x = fu.get();
cout << "Get from child " << x << endl;
return 0;
}
輸出結果如下:
Result is 24
Get from child 24
-
阻塞線程,直到擷取到可用結果std::future<T>::wait
#include <iostream>
#include <future>
#include <thread>
int fib(int n)
{
if (n < 3) return 1;
else return fib(n-1) + fib(n-2);
}
int main()
{
std::future<int> f1 = std::async(std::launch::async, [](){
return fib(20);
});
std::future<int> f2 = std::async(std::launch::async, [](){
return fib(25);
});
std::cout << "waiting...\n";
//主線程在該處阻塞,直到擷取到f1,f2兩個線程到合法的結果
f1.wait();
f2.wait();
std::cout << "f1: " << f1.get() << '\n';
std::cout << "f2: " << f2.get() << '\n';
}
-
和wait_for()
兩個函數成員同wait_until()
中的類似,仍然是僅增加了需要等待的時間,到達等待的時間如仍然無法擷取到合法的傳回值即同樣終止condition_variable
get