2012-03-06 1 views
0

스케쥴러 클래스를 구현하고 싶습니다. 스케쥴러 클래스는 모든 객체가 타임 아웃을 스케쥴하고 필요한 경우 취소 할 수 있습니다. 시간 초과가 만료되면이 정보는 그 시간에 비동기 적으로 시간 초과 설정자/소유자에게 전송됩니다.Windows에서 스케줄러 클래스 구현하기

그래서이 두 가지 기본 클래스 인 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()을 호출합니다. 그러나, 항상 취소 연산을 선점하는 OS에 의해 callback 될 timerFunction 정적 호출이있을 수 있습니다 (예 : mCancelled = true 명령문 바로 뒤에). 이 경우 타임 아웃 인스턴스는 콜백 함수에 의해 삭제됩니다. 콜백 함수가 실행을 완료 한 후 미리 empted cancel() 함수가 다시 실행되면 삭제 된 인스턴스 (mTimerID)의 속성에 액세스하려고 시도합니다. "Delete under # 1"행에서 볼 수 있습니다. 코드.

어떻게 이런 경우를 피할 수 있습니까? Windows multimedia timer with callback argument

+0

어떤 아이디어일까요? – bethoven25

답변

1

Q1 - 나는 그것이 타이머 API에 의해 할당 된 스레드 내에서 호출됩니다 믿습니다

가 있다는 점 유의 하시길 바랍니다이 질문은 previos 여기 내 자신의 하나의 향상된 버전입니다. 확실하지는 않지만 스레드가 매우 높은 우선 순위에서 실행되면 놀라지 않을 것입니다. (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