2012-03-06 10 views
0

私はスケジューラクラスを実装したいと思います。オブジェクトはタイムアウトをスケジューリングし、必要に応じてキャンセルすることができます。タイムアウトが経過すると、この情報はその時点で非同期にタイムアウト設定/所有者に送信されます。Windowsでスケジューラクラスを実装する

したがって、私は2つの基本クラスWindowsTimeoutとWindowsSchedulerを持っています。

class WindowsTimeout 
{ 
    bool mCancelled; 
    int mTimerID; // Windows handle to identify the actual timer set. 
    ITimeoutReceiver* mSetter; 

    int cancel() 
    { 
    mCancelled = true; 

    if (timeKillEvent(mTimerID) == SUCCESS) // Line under question # 1 
    { 
     delete this; // Timeout instance is self-destroyed. 
     return 0; // ok. OS Timer resource given back. 
    } 
    return 1; // fail. OS Timer resource not given back. 
    } 

    WindowsTimeout(ITimeoutReceiver* setter, int timerID) 
    { 
    mSetter = setter; 
    mTimerID = timerID; 
    } 

}; 

class WindowsScheduler 
{ 
    static void CALLBACK timerFunction(UINT uID,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2)  
{ 
    WindowsTimeout* timeout = (WindowsTimeout*) uMsg; 
    if (timeout->mCancelled) 
      delete timeout; 
    else 
      timeout->mDestination->GEN(evTimeout(timeout)); 
} 
WindowsTimeout* schedule(ITimeoutReceiver* setter, TimeUnit t) 
    { 
     int timerID = timeSetEvent(...); 
     if (timerID == SUCCESS) 
     { 
      return WindowsTimeout(setter, timerID); 
     } 
     return 0; 
    } 
}; 

私の質問は以下のとおりです。

Q.1。 WindowsScheduler :: timerFunction()呼び出しが行われると、この呼び出しはどのコンテキストで実行されますか?これは単なるコールバック関数であり、OSコンテキストによって実行されると思います。そうであれば、この呼び出しはすでに実行中の他のタスクを先取りしますか?コールバックの優先度は他のどのユーザータスクよりも高いのですか?

Q.2。タイムアウト設定がタイムアウトをキャンセルしたい場合、WindowsTimeout :: cancel()を呼び出します。 しかし、キャンセル操作を先取りして、例えば、mCancelled = trueステートメントの直後など、OSによってコールバックされるtimerFunction静的呼び出しが常に存在する可能性があります。このような場合、タイムアウトインスタンスはコールバック関数によって削除されます。 コールバック関数の実行が完了したあとで、先取りされたcancel()関数が再び呼び出されると、削除されたインスタンス(mTimerID)の属性にアクセスしようとします。コード。

どうすればこのようなケースを回避できますか? - 私はそれがタイマーAPIによって割り当てられたスレッド内で呼び出されると信じてい Windows multimedia timer with callback argument

+0

どうかありますか? – bethoven25

答えて

1

Q1:

この質問は&過去の改良版ここに私自身の一つである、ということに注意してください。私は確信していませんが、スレッドが非常に高い優先順位で実行された場合、私は驚くことはありません。 (Windowsでは、必ずしも他のスレッドを完全に占有するわけではありません。他のスレッドよりも多くのサイクルを取得することを意味します)。

Q2 - 私はこれのための解決策を描き始めましたが、私が思ったより少し難しいと分かりました。個人的には、timerIDをWindowsTimeoutオブジェクトインスタンスにマップするハッシュテーブルを維持します。ハッシュテーブルは、クリティカルセクションで保護されている単純なstd :: mapインスタンスです。タイマーコールバックが発生すると、クリティカルセクションに入り、WindowsTimerインスタンスポインタを取得しようとし、実行されたとしてWindowsTimerインスタンスにフラグを立て、クリティカルセクションを終了して実際にコールバックを実行します。ハッシュテーブルにWindowsTimerインスタンスが含まれていない場合は、呼び出し元が既に削除していることを意味します。ここでは非常に注意してください。上記の独自のコードで

一つ微妙なバグ:あなたはWindowsTimeoutのインスタンスを作成する前に、あなたのスケジュール方法で

WindowsTimeout* schedule(ITimeoutReceiver* setter, TimeUnit t) 
    { 
     int timerID = timeSetEvent(...); 
     if (timerID == SUCCESS) 
     { 
      return WindowsTimeout(setter, timerID); 
     } 
     return 0; 
    } 
}; 

は、それがtimeSetEventによってスケジュールコールバックが返されることは完全に可能です。

+0

お待ちください。ありがとうございます。 – bethoven25

+1

私はまだあなたに解決策を教えてもらえます。しかし、単に「スレッドセーフマップ」に基づいています。 – selbie

関連する問題