我創建了一個boost :: asio :: io_service的包裝來處理OpenGL應用程序的GUI線程上的異步任務。正在使用shared_ptr和weak_ptr來管理std :: function安全的生命週期?
任務可能是由其他線程創建的,所以boost::asio
對於這個目的來說似乎是理想的,並且意味着我不需要用關聯的互斥鎖和鎖定編寫我自己的任務隊列。我希望將每幀的工作都保持在可接受的閾值以下(例如5毫秒),所以我打電話給poll_one
,直到超出所需的預算,而不是致電run
。據我所知,這需要我在發佈新任務時致電reset
,這似乎運作良好。
由於它是短,這裏的整個事情,SANS #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
將執行任務。如果我在mTask
上調用reset
,則weak_ptr
無法鎖定,並且按需要跳過任務。
我的問題真的是所有這些新工具的一個信心:是new std::function<void(void)>(std::bind(...))
一個好的事情要做,並安全的事情來管理一個shared_ptr
?
非常感謝!我想我只能從UI線程中取消任務將被處理的地方來避免競爭條件,但是我會記住這個代碼的線程版本。 – RandomEtc
感謝您的初始化提示呢! – RandomEtc