gpt4 book ai didi

c++ - CreateTimerQueueTimer 回调和竞争条件

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

我在我的应用程序中使用计时器队列,并将指向我自己的 C++ 计时器对象之一的指针作为“参数”传递给回调(在 CreateTimerQueueTimer 中)。然后,我在回调中对对象调用虚拟方法。

Timer 对象的析构函数将确保使用 DeleteTimerQueueTimer() 取消计时器。

static void callback( PVOID param, BOOLEAN timerOrWaitFired )
{
Timer* timer = reinterpret_cast< Timer* >( param );
timer->TimedOut();
}

class Timer
{
public:
Timer();

virtual ~Timer()
{
::DeleteTimerQueueTimer( handle );
}

void Start( double period )
{
::CreateTimerQueueTimer( &handle, ..., &callback, this, ... );
}

virtual void TimedOut() = 0;

...
};

但是,存在一个微妙的竞争条件,如果回调已被调用,但定时器对象在调用 TimedOut() 之前被销毁,应用程序崩溃,因为回调调用虚拟不存在的对象上的方法。甚至更糟的是,它正在被删除。

我确实有适当的互斥锁来控制多线程调用,但我仍然遇到问题。

使用对象指针作为回调参数真的是个好主意吗?由于无法保证线程之间的同步,这对我来说很难闻。

有更好的解决方案吗?其他人做什么?

发生的一件事是保留一组指向每个 Timer 实例的指针(在构造函数中添加,在析构函数中删除)。但我认为这行不通,因为如果 Timer 派生自,我们只会从基类析构函数中的集合中删除指针;如果我们已经开始销毁派生对象,那么损害就已经造成了。

干杯。

最佳答案

使用对象指针作为回调函数参数的概念本身并不坏。但是,您显然需要在最后一个回调退出后开始销毁。

因此,我根本不会将 Timer 抽象化并派生自它。我会使用另一个抽象类 TimerImpl 并使 Timer 类使用 TimerImpl 实例:

class Timer
{
TimerInstance* impl;
void TimeOut() { impl->TimeOut(); }
public:
~Timer() {
... make sure the timer has ended and wont fire again after this line...
delete impl;
}
}

struct TimerImpl
{
virtual void TimeOut()=0;
virtual ~TimerImpl();
}

这样,您可以确保破坏不会在您说完之前开始。

第二件事是,你必须等待最后一个计时器事件耗尽。根据MSDN doc , 你可以调用

DeleteTimerQueueTimer(TimerQueue, Timer, INVALID_HANDLE_VALUE)

关于c++ - CreateTimerQueueTimer 回调和竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/476865/

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