C++並發練習 筆記(一)STL<future>中的packaged_task
来源:互联网 发布:成都知美术馆怎么去 编辑:程序博客网 时间:2024/06/08 13:23
今天在偶然在找尋有關OpenCV的演算法實作方法時,看到了大牛們使用了packaged_task的這樣一個函數。
自己是沒見過的,當然就趕快操起google搜尋及手邊資料進行搜查。
並自己在網絡上找了一些視頻資源加以學習,並在此留下筆記,用來強化記憶及供人及自己日後參考。
推薦學習視頻連結:youtube:C++ Threading #9: packaged_task
Bo qian大神的一系列視頻講的真是不錯,每次都能從他的代碼中學到許多東西,因此真心推薦。
進入正文:
首先先附上來自cppreference.com的C++字典說明。來源連結
packaged_task被定義在頭文件<future>當中,而看到<future>這個頭文件,應該很多同學都跟我一樣心裡有了個底,這是個將會是個異步函數的調用
,就跟我們想的一樣,它確實就是如此。
這個模板函數能封裝任何callable的物件,包括function,lambda,bind expresion,function object,)而被包裝在其中的函數
將會被以異步的方式進行調用。
這是它的建構子。
class packaged_task<R(Args...)>;(2)(since C++11)
恩..確實有些難懂,不如先來看一下大至的使用方法
int Factorial(int N)//被包裝函數的宣告及實現{int res=1;for(int i=N;i>1;i--)res*=i;std::cout<<"Result is"<<res<<std::endl;return res;}std::deque<std::packaged_task<int()>> task_q;//packeged_task的容器int main(){std::packaged_task<int()> t(bind(Fatorial,6)); //包裝函數task_q.push_back(t);//將被包裝的函數丟入容器中return 0;}
在main函數中 std::packaged_task<>模板函數所包含的的是int();
其中int 代表的是被包裝函數的返回值,()不加入任何類型代表不帶任何參數,假如有參數則可以寫成如下
std::packaged_task<int (int ,string&)>//接受兩個參數 int,string&,並返回int
而在本範例中,要被包裝的函數是 int Factorial (int),理應當寫成
std::packaged_task<int (int)>//接受一個參數 int,並返回int但是卻寫成了
std::packaged_task<int ()>//不接受參數,並返回int仔細看一下後面,原來被包裝的函數與參數綁定了,bind(Factorial,6),使得原本的模版函數不能在接受更多參數
故而最後寫成
std::packaged_task<int()> t(bind(Factorial,6))//不接受參數,並返回int,同時包裝了bind function obj (Factorial,6)這是在應用上須要相當注意的地方。
t現在代表了一個異步調用,如果在之後想要獲取它的值,可以直接寫以下代碼來獲取它的值
std::future<int> nAsyncResult=t.get_future()但是你看到接下來的代碼
task_q.push_back(t);我們將它放入了一個雙向對列之中,這是為了接下來比較有挑戰性的法,同時使用thread和異步調用。
來看一下剛剛範例的進階版,斜體加粗的部分代表跟剛剛比較多出來的部分。
int Factorial(int N){int res=1;for(int i=N;i>1;i--)res*=i;cout<<"Result is"<<res<<endl;return res;}std::deque<std::packaged_task<int()>> task_q;void thread_1()//線程函數的實作{std::packaged_task<int()>t;//宣到一個封裝int()函數類型的package_taskt=std::move(task_q.front());//t=容器最上方的值,由於容器中的右值不再使用,所以利用move語句,將右值直接給t,而不是拷貝一份。t();//執行t}int main(){std::thread t1(thread_1);std::packaged_task<int()> t(bind(Fatorial,6));task_q.push_back(t);t1.join();//確保主線程等待執行緒結束return 0;}
這樣代碼就成了異步的生產與消費者線程模型。
但這樣的代碼仍然沒有考慮到資源競爭,以及線程同步的問題,讓我們繼續完善它。(使用Mutex 跟lock_guard)
int Factorial(int N){int res=1;for(int i=N;i>1;i--)res*=i;cout<<"Result is"<<res<<endl;return res;}std::deque<std::packaged_task<int()>> task_q;std::mutex mu//宣告臨界區mutexvoid thread_1(){std::packaged_task<int()>t;{std::lock_guard<std::mutex> locker(mu);//lock guard必須與生產者(主線程使用同一個臨界區t=std::move(task_q.front());task_q.pop_front();}t();}int main(){std::thread t1(thread_1);std::packaged_task<int()> t(bind(Fatorial,6));std::future<int> nFuture=t.get_future();//在將來以異步的方式獲取該值{std::lock_guard<std::mutex> locker(mu);//lock guard必須與消費者(線程1)使用同一個臨界區task_q.push_back(std::move(t));}t1.join();return 0;}
但這樣仍無法保證,生產者將工作塞入容器前,消費者不能先將物品取出來,必須確認容器不為空時才繼續執行動作,因此我們再導入
condition_variable
int Factorial(int N){int res=1;for(int i=N;i>1;i--)res*=i;cout<<"Result is"<<res<<endl;return res;}std::deque<std::packaged_task<int()>> task_q;std::mutex mustd::condition_variable cond;//宣告condition_variablevoid thread_1(){std::packaged_task<int()>t;{std::unique_lock<std::mutex> locker(mu);//使用condition_variable,lock的方法必須為unique_lockcond.wait(locker,[](){return !task_q.empty();});//使用lambda function來指示當容器為空,則不執行任何動作。t=std::move(task_q.front());task_q.pop_front();}t();}int main(){std::thread t1(thread_1);std::packaged_task<int()> t(bind(Fatorial,6));std::future<int> nFuture=t.get_future();{std::lock_guard<std::mutex> locker(mu);task_q.push_back(std::move(t));}cond.notify_one();//通知另一個在等待的線程可以繼續執行,如果多線程使用notify_all()cout<<fu.get();//獲取異步調用的值,並打印t1.join();return 0;}
- C++並發練習 筆記(一)STL<future>中的packaged_task
- future, packaged_task promise
- C++11并发编程指南四(<future> 详解二 std::packaged_task 介绍)
- C++11多线程(六):《<future> 详解二:std::packaged_task 介绍》
- C++11之future,promise,packaged_task,async详解
- C++11中future,promise,packaged_task和async介绍
- C++并发实战13:std::future、std::async、std::promise、std::packaged_task
- C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)
- C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)
- C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)
- C++STL中的容器
- c++stl中的stack
- STL中的函数对象(一)
- C++STL容器(一)
- 用C++11的std::async代替线程的创建and std::future、std::promise和std::packaged_task
- C/C++中的STL函数库
- c++STL 中的copy函数
- C/C++中的STL库
- 巴西游戏如何做好本地化?
- 在win10平台下快速查找占用端口的服务
- linux中强大且常用命令:find、grep
- 汉诺塔——递归入门
- 深入理解HTTP协议
- C++並發練習 筆記(一)STL<future>中的packaged_task
- LaTeX section不带编号同时书签生效
- 程序员必知的8大排序
- C#54课的主要内容
- ZooKeeper系列之二:Zookeeper的安装和配置
- <c:forEach>标签
- Spring框架_事物管理器的配置
- 常用的五大bug管理工具的优缺点
- snprintf使用注意点