gpt4 book ai didi

c++ - 使用 shared_ptr 和 weak_ptr 来管理 std::function 的生命周期是否安全?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:45:40 27 4
gpt4 key购买 nike

我已经围绕 boost::asio::io_service 创建了一个包装器来处理 OpenGL 应用程序的 GUI 线程上的异步任务。

任务可能是从其他线程创建的,因此 boost::asio似乎是这个目的的理想选择,这意味着我不需要编写自己的带有关联互斥锁和锁定的任务队列。我想将每帧完成的工作保持在可接受的阈值以下(例如 5 毫秒),所以我调用 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_ptrmTask大约然后 io_service将执行任务。如果我调用 resetmTask然后是 weak_ptr无法锁定并根据需要跳过任务。

我的问题确实是对所有这些新工具的信心之一:是 new std::function<void(void)>( std::bind( ... ) )shared_ptr 可以做的一件好事,也是一件安全的事?

最佳答案

是的,这是安全的。

对于代码:

VoidFunc *task = new VoidFunc( std::bind(&MyApp::doUiTask, this) );
mTask = std::shared_ptr<VoidFunc>( task );

只是做:

mTask.reset(new VoidFunc( std::bind(&MyApp::doUiTask, this) ) );

(以及其他地方)。

请记住,您需要处理竞争条件,即在重置 shared_ptr 之前可能会锁定 weak_ptr,从而使回调保持事件状态,因此您偶尔会看到回调,即使您去了沿代码路径重置回调 shared_ptr。

关于c++ - 使用 shared_ptr 和 weak_ptr 来管理 std::function 的生命周期是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8040925/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com