OpenGLアプリケーションのGUIスレッドで非同期タスクを処理するためにboost :: asio :: io_serviceのラッパーを作成しました。shared_ptrとweak_ptrを使用してstd :: function safeのライフタイムを管理していますか?
他のスレッドからタスクが作成される可能性があります。boost::asio
は、この目的には理想的と思われ、関連するmutexとロックを持つ独自のタスクキューを作成する必要はありません。私はrun
を呼び出すのではなく、希望の予算を超過するまでpoll_one
を呼び出していますので、各フレームで行われた作業を許容可能なしきい値(たとえば5ms)以下に保ちたいと思います。私が知る限り、新しい仕事が投稿されるたびにreset
に電話する必要があります。これはうまくいくようです。それは短いですので
、ここでは、全体のことだサンセリフ#include
:
typedef std::function<void(void)> VoidFunc;
typedef std::shared_ptr<class UiTaskQueue> UiTaskQueueRef;
class UiTaskQueue {
public:
static UiTaskQueueRef create()
{
return UiTaskQueueRef(new UiTaskQueue());
}
~UiTaskQueue() {}
// normally just hand off the results of std/boost::bind to this function:
void pushTask(VoidFunc f)
{
mService.post(f);
mService.reset();
}
// called from UI thread; defaults to ~5ms budget (but always does one call)
void update(const float &budgetSeconds = 0.005f)
{
// getElapsedSeconds is a utility function from the GUI lib I'm using
const float t = getElapsedSeconds();
while (mService.poll_one() && getElapsedSeconds() - t < budgetSeconds);
}
private:
UiTaskQueue() {}
boost::asio::io_service mService;
};
私は私のメインのアプリクラスでUiTaskQueueRefのインスタンスを保持し、私のアプリのアニメーションループ内からmUiTaskQueue->update()
を呼び出します。
このクラスの機能を拡張して、タスクをキャンセルできるようにしたいと考えています。以前の実装(ほぼ同じインターフェイスを使用)では、各タスクに数字のIDが返され、このIDを使用してタスクをキャンセルすることができました。しかし今、キューと関連するロックの管理はboost::asio
によって処理されています。これを行うにはどうすればよいか分かりません。
私はshared_ptr
でキャンセルする場合があります任意のタスクをラップし、タスクにweak_ptr
を格納し、それがio_service
に渡すことができるよう()
オペレータを実装ラッパーオブジェクトを作成することによって試みを行いました。それは次のようになります。私は、キューにポスト解約タスクが使用して
void pushTask(std::weak_ptr<VoidFunc> f)
{
mService.post(CancelableTask(f));
mService.reset();
}
:
struct CancelableTask {
CancelableTask(std::weak_ptr<VoidFunc> f): mFunc(f) {}
void operator()(void) const {
std::shared_ptr<VoidFunc> f = mFunc.lock();
if (f) {
(*f)();
}
}
std::weak_ptr<VoidFunc> mFunc;
};
私は、このようになります私のpushTask
メソッドのオーバーロードを持っ
std::function<void(void)> *task = new std::function<void(void)>(boost::bind(&MyApp::doUiTask, this));
mTask = std::shared_ptr< std::function<void(void)> >(task);
mUiTaskQueue->pushTask(std::weak_ptr< std::function<void(void)> >(mTask));
または、VoidFunc
typedefを使用してください。
VoidFunc *task = new VoidFunc(std::bind(&MyApp::doUiTask, this));
mTask = std::shared_ptr<VoidFunc>(task);
mUiTaskQueue->pushTask(std::weak_ptr<VoidFunc>(mTask));
shared_ptr
をmTask
にしておけば、io_service
はそのタスクを実行します。 reset
をmTask
と呼び出すと、weak_ptr
はロックできず、タスクは必要に応じてスキップされます。
私の質問は、これらすべての新しいツールでは本当に自信があります:new std::function<void(void)>(std::bind(...))
OKのことです。shared_ptr
で管理するのは安全でしょうか?
ありがとうございました!私は、タスクが処理されるUIスレッドから取り消すだけで競合状態を回避できると思いますが、このコードのスレッドバージョンでは注意しています。 – RandomEtc
あまりにも初期化のヒントありがとう! – RandomEtc