目次
3つ目は、std :: futureとstd :: asyncを使用する
2つのクラス間の非同期シナリオを考えてみましょう。クライアントは特定のタスクを処理するためにクラスAを呼び出し、AはBに処理を実行して結果を返すように委託する必要があります。すべてが非同期で実行されます。つまり、関数はすぐに返され、その後計算はバックグラウンドで実行され、通知が完了します。発信者。
1つは、関数ポインタを使用する
クラスBには、関数ポインターを受け取るためのSetCallBackインターフェイスが必要です。ここでは、std :: functionを使用して実現します。B. ProcessAsyncタスクが実行されると、別のスレッドが開始され、デタッチされて、より長いバックグラウンド計算が実行されます(ここでは、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に設定するときに、ラムダ式またはstd :: bindのいずれかを使用できます。これは、個人の好みによって異なります。Aがコールバックを受信したら、計算結果を出力します。
#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は、純粋仮想メソッドOnProcessDoneを持つインターフェイスクラスListenerを提供し、AはB :: Listenerを継承してこの仮想メソッドを実装するために、新しいMyListenerを宣言できます。
ここでは、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;
};
3つ目は、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を別のスレッドに渡すときに移動することに注意してください。
#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;
};