目錄
一、使用函式指標
二、實作虛方法
三、使用std::future和std::async
考慮兩個類之間的異步場景:客戶端呼叫類A處理某個任務,A需要委托B進行一些處理并回傳結果;并且都是異步進行,即函式迅速回傳之后在后臺進行計算,完畢后通知呼叫者,
一、使用函式指標
類B需要有SetCallBack介面來接收函式指標,此處我們用std::function來實作, B在進行ProcessAsync任務時另起一個執行緒并detach掉去進行較長時間的后臺計算(此處用std::this_thread::sleep_for來模擬長時間計算),計算完成后通過剛才設定進來的函式指標來通知呼叫者,
#include <iostream>
#include <functional>
#include <thread>
class B
{
public:
void SetCallBack(const std::function<void(double)> &cb) {
m_callback = cb;
}
void ProcessAsync() {
printf("class B, create thread to compute and return immediately\n");
std::thread th(&B::ProcessReal, this);
th.detach();
}
private:
void ProcessReal() {
printf("class B, Process for a long time...\n");
std::this_thread::sleep_for(std::chrono::seconds(3));
if (m_callback) {
printf("callback\n");
m_callback(3.72);
}
}
std::function<void(double)> m_callback;
};
類A在向類B設定回呼時既可以用lambda運算式也可以用std::bind,這個看個人喜好, A收到回呼時列印計算結果result,
#include <iostream>
#include <memory>
#include <functional>
#include "B.h"
class A
{
public:
void DoTask() {
printf("class A, DoTask\n");
m_b = std::make_shared<B>();
//m_b->SetCallBack([this](double res) {return OnProcessDone(res);});
m_b->SetCallBack(std::bind(&A::OnProcessDone, this, std::placeholders::_1));
m_b->ProcessAsync();
}
private:
void OnProcessDone(double result) {
printf("OnProcessDone, result = %f\n", result);
}
std::shared_ptr<B> m_b{nullptr};
};
主函式就不多說了
#include <thread>
#include <chrono>
#include "A.h"
int main() {
A a;
a.DoTask();
std::this_thread::sleep_for(std::chrono::seconds(5));
return 0;
}
二、實作虛方法
B提供一個介面類Listener,介面類中有一個純虛方法OnProcessDone;而A中可以新宣告一個MyListener來繼承B::Listener,并實作這個虛方法,
此處A::MyListener和B::Listener都宣告成了內部類,這樣做的好處是:內部類默認是外部類的友元,則A::MyListener就可以訪問類A的私有成員,在回呼需要訪問私有成員時這種寫法十分方便,
#include <iostream>
#include <functional>
#include <thread>
#include <memory>
class B
{
public:
class Listener {
public:
virtual void OnProcessDone(double result) = 0;
};
void SetCallBack(const std::shared_ptr<Listener> &cb) {
m_callback = cb;
}
void ProcessAsync() {
printf("class B, create thread to compute and return immediately\n");
std::thread th(&B::ProcessReal, this);
th.detach();
}
private:
void ProcessReal() {
printf("class B, Process for a long time...\n");
std::this_thread::sleep_for(std::chrono::seconds(3));
if (m_callback) {
printf("callback\n");
m_callback->OnProcessDone(3.72);
}
}
std::shared_ptr<Listener> m_callback;
};
#include <iostream>
#include <memory>
#include <functional>
#include "B.h"
class A
{
public:
void DoTask() {
printf("class A, DoTask\n");
m_b = std::make_shared<B>();
m_b->SetCallBack(std::make_shared<MyListener>(this));
m_b->ProcessAsync();
}
private:
class MyListener : public B::Listener {
public:
MyListener(A *a) : m_a(a) {}
void OnProcessDone(double result) {
printf("OnProcessDone, result = %f\n", result);
m_a->m_res = result;
}
private:
A *m_a;
};
std::shared_ptr<B> m_b{nullptr};
double m_res;
};
三、使用std::future和std::async
在類A中啟動一個std::async,將B的同步處理函式變成異步的,這樣就不需要向B設定回呼了,B的實作會非常簡單, A中在需要計算結果時呼叫future的.get()就可以取到結果,
#include <iostream>
#include <thread>
class B
{
public:
double ProcessSync() {
printf("class B, Process for a long time...\n");
std::this_thread::sleep_for(std::chrono::seconds(3));
return 3.72;
}
};
要注意std::future是不可拷貝的,所以把future傳到另一個執行緒時要move過去,
#include <iostream>
#include <memory>
#include <functional>
#include <future>
#include "B.h"
class A
{
public:
void DoTask() {
printf("class A, DoTask\n");
m_b = std::make_shared<B>();
std::future<double> fut = std::async(std::bind(&B::ProcessSync, m_b));
std::thread th(&A::WaitForProcessDone, this, std::move(fut));
th.detach();
}
private:
void WaitForProcessDone(std::future<double> &&fut) {
double result = fut.get();
printf("ProcessDone, result = %f\n", result);
m_res = result;
}
std::shared_ptr<B> m_b{nullptr};
double m_res;
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/253997.html
標籤:其他
下一篇:小程式-API
