我正在我的应用程序中使用计时器队列,并将指针传递给我自己的一个C++ Timer对象作为回调的"参数"(在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;
...
};
Run Code Online (Sandbox Code Playgroud)
但是,有一个微妙的竞争条件,如果已经调用了回调,但是在调用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();
}
Run Code Online (Sandbox Code Playgroud)
这样,您就可以确保破坏不会在您说完之后开始。
第二件事是,你必须等待最后一个计时器事件烧完。根据MSDN 文档,您可以通过调用来完成
DeleteTimerQueueTimer(TimerQueue, Timer, INVALID_HANDLE_VALUE)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6662 次 |
| 最近记录: |