アプリケーションでタイマー キューを使用しており、独自の C++ タイマー オブジェクトの 1 つへのポインターをコールバックへの「パラメーター」として渡します (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() の呼び出し前にタイマー オブジェクトが破棄された場合、コールバックが存在しないオブジェクトの仮想メソッドを呼び出すため、アプリがクラッシュするという微妙な競合状態があります。さらに悪いことに、削除中です。
マルチスレッド呼び出しを制御するためにミューテックスを配置していますが、それでも問題が発生します。
コールバック パラメータとしてオブジェクト ポインタを使用することは本当に良い考えですか? スレッド間の同期が保証されていないため、私には悪臭がします。
より良い解決策はありますか?他の人は何をしますか?
発生することの 1 つは、すべての単一の Timer インスタンスへのポインターのセットを保持することです (コンストラクターで追加し、デストラクターで削除します)。しかし、Timer がから派生している場合、基本クラスのデストラクタのセットからポインタを削除するだけなので、これは機能しないと思います。派生オブジェクトの破壊を開始した場合、損傷はすでに発生しています。
乾杯。