OpenGLアプリケーションのGUIスレッドで非同期タスクを処理するために、boost :: asio::io_serviceのラッパーを作成しました。
タスクは他のスレッドから作成される可能性があるboost::asio
ため、この目的には理想的であり、ミューテックスとロックを関連付けて独自のタスクキューを作成する必要がないことを意味します。各フレームで行われる作業を許容可能なしきい値(たとえば5ms)未満に保ちたいので、をpoll_one
呼び出すのではなく、目的の予算を超えるまで呼び出しrun
ます。私が知る限り、これには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
。次のようになります。
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
次のようなメソッドのオーバーロードがあります。
void pushTask( std::weak_ptr<VoidFunc> f )
{
mService.post( CancelableTask(f) );
mService.reset();
}
次に、以下を使用してキャンセル可能なタスクをキューに投稿します。
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
ロックできず、タスクは必要に応じてスキップされます。
私の質問は、これらすべての新しいツールに対する自信の1つです。実行しても問題はnew std::function<void(void)>( std::bind( ... ) )
なく、安全に管理できるのshared_ptr
でしょうか。