OpenGL 응용 프로그램의 GUI 스레드에서 비동기 작업을 처리하기 위해 boost :: asio :: io_service에 대한 래퍼를 만들었습니다.shared_ptr 및 weak_ptr을 사용하여 std :: function safe의 수명을 관리합니까?
다른 스레드에서 작업을 생성 할 수 있으므로 boost::asio
이 이상적으로 보이고 관련 뮤텍스 및 잠금 기능이있는 자체 작업 큐를 작성할 필요가 없습니다. 허용되는 임계 값 (예 : 5ms) 아래에서 각 프레임의 작업을 계속 유지하여 run
을 호출하는 것보다 원하는 예산이 초과 될 때까지 poll_one
으로 전화를 걸겠습니다. 제가 말할 수있는 한, 새로운 작업이 게시 될 때마다 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;
};
I는 다음과 같습니다 내 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