怎么正常结束多媒体定时器。
一、采用TIME_CALLBACK_EVENT_SET。
#define PLAYERTICK_H
class _DS_EXT_DVRBASE_CLASS CTickUser
{
public:
CTickUser();
virtual ~CTickUser();
void SetSpeed(int nSpeed);
void SetMiniSecs(int nMinisecs);
int GetFastSpeed();
BOOL Tick();
private:
int m_nMinisecs;
int m_nSlowSpeed; //if it decelerating, nMinisecs * nSlowSpeed is the tick cycle.
//if it accelerating, keep the speed nMinisecs.but executing GetFrameEx function
//more times per tick.
int m_nTickCount;
int m_nFastSpeed;
};
struct ITickNotify
{
virtual void OnTickNotify() = 0;
};
class _DS_EXT_DVRBASE_CLASS CCheckTick
{
public:
CCheckTick();
virtual ~CCheckTick();
void KillPlayerTimer();
void SetPlayerTimer();
void SetTickNotify(ITickNotify *pTickNotify);
private:
HANDLE m_hDoEventThread;
DWORD m_dwEventThreadID;
HANDLE m_hEventEndStatus;
static DWORD WINAPI DoTimerEventThread(LPVOID lpParam);
void SetPlayerTimer(int nMiniSeconds);
int m_nPlayerTimerID;
ITickNotify *m_pTickNotify;
HANDLE m_hTimeEvent;
};
#endif
#include "stdafx.h"
#include "PlayerTick.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CTickUser::CTickUser()
{
m_nMinisecs = 40;
m_nSlowSpeed = 1;
m_nFastSpeed = 1;
m_nTickCount = 0;
}
CTickUser::~CTickUser()
{
m_nMinisecs = 40;
m_nSlowSpeed = 1;
}
void CTickUser::SetMiniSecs(int nMinisecs)
{
m_nMinisecs = nMinisecs;
// TRACE("SetMiniSecs %d/n", nMinisecs);
}
int CTickUser::GetFastSpeed()
{
return m_nFastSpeed;
}
BOOL CTickUser::Tick()
{
int nTickTime = m_nTickCount * 40 + 40;
if(nTickTime >= m_nSlowSpeed * m_nMinisecs)
{
// TRACE("nTickTime %d, m_nSlowSpeed %d, m_nMinisecs %d/n",
// nTickTime, m_nSlowSpeed, m_nMinisecs);
m_nTickCount = 0;
return TRUE;
}
// TRACE("nTickTime %d, m_nSlowSpeed * m_nMinisecs %d, m_nTickCount %d/n",
// nTickTime, m_nSlowSpeed * m_nMinisecs, m_nTickCount);
m_nTickCount++;
return FALSE;
}
void CTickUser::SetSpeed(int nSpeed)
{
if(nSpeed == 0)
{
m_nFastSpeed = 1;
m_nSlowSpeed = 1;
}
else if(nSpeed < 0)
{
m_nFastSpeed = 1;
m_nSlowSpeed = - nSpeed + 1;
}
else
{
m_nFastSpeed = nSpeed + 1;
m_nSlowSpeed = 1;
}
}
//when calling the timeKillEvent function,
//the callback is forced stopping executing.
//so don't need the event object m_hTimeComing pointing.
CCheckTick::CCheckTick()
{
m_pTickNotify = NULL;
m_nPlayerTimerID = -1;
m_hEventEndStatus = NULL;
m_hDoEventThread = NULL;
m_hTimeEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
}
CCheckTick::~CCheckTick()
{
if(m_hTimeEvent != NULL)
{
CloseHandle(m_hTimeEvent);
m_hTimeEvent = NULL;
}
}
#define TIME_KILL_SYNCHRONOUS 0x0100
void CCheckTick::SetPlayerTimer(int nMiniSeconds)
{
KillPlayerTimer();
UINT m_nwAccuracy = 1; //定时器精度参数
m_nPlayerTimerID = timeSetEventWz(nMiniSeconds, m_nwAccuracy,
(LPTIMECALLBACK)m_hTimeEvent, NULL, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET);
}
void CCheckTick::SetPlayerTimer()
{
this->SetPlayerTimer(40);
m_hEventEndStatus = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hDoEventThread = CreateThread(NULL, NULL, DoTimerEventThread, this, 0,
&m_dwEventThreadID);
}
void CCheckTick::KillPlayerTimer()
{
if(m_nPlayerTimerID != -1)
{
ASSERT(m_nPlayerTimerID != -1);
timeKillEventWz(m_nPlayerTimerID);
m_nPlayerTimerID = -1;
TRACE("timeKillEvent/n");
// WaitForSingleObject(m_hTimeComing, 5000);
// ASSERT(WaitForSingleObject(m_hTimeComing, 1000) == WAIT_OBJECT_0);
}
if(m_hEventEndStatus != NULL)
{
SetEvent(m_hEventEndStatus);
WaitForSingleObject(m_hDoEventThread, 10000);
CloseHandle(m_hEventEndStatus);
m_hEventEndStatus = NULL;
CloseHandle(m_hDoEventThread);
m_hDoEventThread = NULL;
}
}
void CCheckTick::SetTickNotify(ITickNotify *pTickNotify)
{
m_pTickNotify = pTickNotify;
}
DWORD WINAPI CCheckTick::DoTimerEventThread(LPVOID lpParam)
{
CCheckTick *pCheckTick = (CCheckTick*)lpParam;
while(TRUE)
{
//ê?·??áê???3ì
if(WaitForSingleObject(pCheckTick->m_hEventEndStatus, 0) == WAIT_OBJECT_0)
{
break;
}
if(WaitForSingleObject(pCheckTick->m_hTimeEvent, 40) == WAIT_OBJECT_0)
{
ASSERT(pCheckTick != NULL);
ASSERT(pCheckTick->m_pTickNotify != NULL);
pCheckTick->m_pTickNotify->OnTickNotify();
}
}
return 0;
}
二、采用TIME_KILL_SYNCHRONOUS。
#ifndef PLAYERTICK_H
#define PLAYERTICK_H
class _DS_EXT_DVRBASE_CLASS CTickUser
{
public:
CTickUser();
virtual ~CTickUser();
void SetSpeed(int nSpeed);
void SetMiniSecs(int nMinisecs);
int GetFastSpeed();
BOOL Tick();
private:
int m_nMinisecs;
int m_nSlowSpeed; //if it decelerating, nMinisecs * nSlowSpeed is the tick cycle.
//if it accelerating, keep the speed nMinisecs.but executing GetFrameEx function
//more times per tick.
int m_nTickCount;
int m_nFastSpeed;
};
struct ITickNotify
{
virtual void OnTickNotify() = 0;
};
class _DS_EXT_DVRBASE_CLASS CCheckTick
{
public:
CCheckTick();
virtual ~CCheckTick();
void KillPlayerTimer();
void SetPlayerTimer();
void SetTickNotify(ITickNotify *pTickNotify);
private:
static void CALLBACK PlayerTimer(UINT wTimerID,UINT nMsg,DWORD dwUser,DWORD dw1,DWORD
dw2);
void SetPlayerTimer(int nMiniSeconds);
int m_nPlayerTimerID;
ITickNotify *m_pTickNotify;
static HANDLE m_hTimeComing;
};
#endif
#include "stdafx.h"
#include "PlayerTick.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CTickUser::CTickUser()
{
m_nMinisecs = 40;
m_nSlowSpeed = 1;
m_nFastSpeed = 1;
m_nTickCount = 0;
}
CTickUser::~CTickUser()
{
m_nMinisecs = 40;
m_nSlowSpeed = 1;
}
void CTickUser::SetMiniSecs(int nMinisecs)
{
m_nMinisecs = nMinisecs;
// TRACE("SetMiniSecs %d/n", nMinisecs);
}
int CTickUser::GetFastSpeed()
{
return m_nFastSpeed;
}
BOOL CTickUser::Tick()
{
int nTickTime = m_nTickCount * 40 + 40;
if(nTickTime >= m_nSlowSpeed * m_nMinisecs)
{
// TRACE("nTickTime %d, m_nSlowSpeed %d, m_nMinisecs %d/n",
// nTickTime, m_nSlowSpeed, m_nMinisecs);
m_nTickCount = 0;
return TRUE;
}
// TRACE("nTickTime %d, m_nSlowSpeed * m_nMinisecs %d, m_nTickCount %d/n",
// nTickTime, m_nSlowSpeed * m_nMinisecs, m_nTickCount);
m_nTickCount++;
return FALSE;
}
void CTickUser::SetSpeed(int nSpeed)
{
if(nSpeed == 0)
{
m_nFastSpeed = 1;
m_nSlowSpeed = 1;
}
else if(nSpeed < 0)
{
m_nFastSpeed = 1;
m_nSlowSpeed = - nSpeed + 1;
}
else
{
m_nFastSpeed = nSpeed + 1;
m_nSlowSpeed = 1;
}
}
//when calling the timeKillEvent function,
//the callback is forced stopping executing.
//so don't need the event object m_hTimeComing pointing.
HANDLE CCheckTick::m_hTimeComing = CreateEvent(NULL, TRUE, TRUE, NULL);
CCheckTick::CCheckTick()
{
m_pTickNotify = NULL;
m_nPlayerTimerID = -1;
}
CCheckTick::~CCheckTick()
{
if(m_hTimeComing != NULL)
{
CloseHandle(m_hTimeComing);
m_hTimeComing = NULL;
}
}
#define TIME_KILL_SYNCHRONOUS 0x0100
void CCheckTick::SetPlayerTimer(int nMiniSeconds)
{
KillPlayerTimer();
UINT m_nwAccuracy = 1; //定时器精度参数
m_nPlayerTimerID = timeSetEvent(nMiniSeconds, m_nwAccuracy,
PlayerTimer, (DWORD)this, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
}
void CCheckTick::SetPlayerTimer()
{
this->SetPlayerTimer(40);
}
void CCheckTick::KillPlayerTimer()
{
if(m_nPlayerTimerID != -1)
{
ASSERT(m_nPlayerTimerID != -1);
timeKillEvent(m_nPlayerTimerID);
m_nPlayerTimerID = -1;
TRACE("timeKillEvent/n");
// ASSERT(WaitForSingleObject(m_hTimeComing, 10000) == WAIT_OBJECT_0);
}
}
void CCheckTick::SetTickNotify(ITickNotify *pTickNotify)
{
m_pTickNotify = pTickNotify;
}
void CCheckTick::PlayerTimer(UINT wTimerID, UINT nMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
TRACE("ResetEvent/n");
// ResetEvent(CCheckTick::m_hTimeComing);
CCheckTick *pCheckTick = (CCheckTick*)dwUser;
// TRACE("PlayerTimer/n");
ASSERT(pCheckTick != NULL);
ASSERT(pCheckTick->m_pTickNotify != NULL);
pCheckTick->m_pTickNotify->OnTickNotify();
// SetEvent(CCheckTick::m_hTimeComing);
TRACE("SetEvent/n");
}
三、采用事件对象。
#ifndef PLAYERTICK_H
#define PLAYERTICK_H
class _DS_EXT_DVRBASE_CLASS CTickUser
{
public:
CTickUser();
virtual ~CTickUser();
void SetSpeed(int nSpeed);
void SetMiniSecs(int nMinisecs);
int GetFastSpeed();
BOOL Tick();
private:
int m_nMinisecs;
int m_nSlowSpeed; //if it decelerating, nMinisecs * nSlowSpeed is the tick cycle.
//if it accelerating, keep the speed nMinisecs.but executing GetFrameEx function
//more times per tick.
int m_nTickCount;
int m_nFastSpeed;
};
struct ITickNotify
{
virtual void OnTickNotify() = 0;
};
class _DS_EXT_DVRBASE_CLASS CCheckTick
{
public:
CCheckTick();
virtual ~CCheckTick();
void KillPlayerTimer();
void SetPlayerTimer();
void SetTickNotify(ITickNotify *pTickNotify);
private:
static void CALLBACK PlayerTimer(UINT wTimerID,UINT nMsg,DWORD dwUser,DWORD dw1,DWORD
dw2);
void SetPlayerTimer(int nMiniSeconds);
int m_nPlayerTimerID;
ITickNotify *m_pTickNotify;
static HANDLE m_hTimeComing;
};
#endif
#include "stdafx.h"
#include "PlayerTick.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CTickUser::CTickUser()
{
m_nMinisecs = 40;
m_nSlowSpeed = 1;
m_nFastSpeed = 1;
m_nTickCount = 0;
}
CTickUser::~CTickUser()
{
m_nMinisecs = 40;
m_nSlowSpeed = 1;
}
void CTickUser::SetMiniSecs(int nMinisecs)
{
m_nMinisecs = nMinisecs;
// TRACE("SetMiniSecs %d/n", nMinisecs);
}
int CTickUser::GetFastSpeed()
{
return m_nFastSpeed;
}
BOOL CTickUser::Tick()
{
int nTickTime = m_nTickCount * 40 + 40;
if(nTickTime >= m_nSlowSpeed * m_nMinisecs)
{
// TRACE("nTickTime %d, m_nSlowSpeed %d, m_nMinisecs %d/n",
// nTickTime, m_nSlowSpeed, m_nMinisecs);
m_nTickCount = 0;
return TRUE;
}
// TRACE("nTickTime %d, m_nSlowSpeed * m_nMinisecs %d, m_nTickCount %d/n",
// nTickTime, m_nSlowSpeed * m_nMinisecs, m_nTickCount);
m_nTickCount++;
return FALSE;
}
void CTickUser::SetSpeed(int nSpeed)
{
if(nSpeed == 0)
{
m_nFastSpeed = 1;
m_nSlowSpeed = 1;
}
else if(nSpeed < 0)
{
m_nFastSpeed = 1;
m_nSlowSpeed = - nSpeed + 1;
}
else
{
m_nFastSpeed = nSpeed + 1;
m_nSlowSpeed = 1;
}
}
//when calling the timeKillEvent function,
//the callback is forced stopping executing.
//so don't need the event object m_hTimeComing pointing.
HANDLE CCheckTick::m_hTimeComing = CreateEvent(NULL, TRUE, TRUE, NULL);
CCheckTick::CCheckTick()
{
m_pTickNotify = NULL;
m_nPlayerTimerID = -1;
}
CCheckTick::~CCheckTick()
{
if(m_hTimeComing != NULL)
{
CloseHandle(m_hTimeComing);
m_hTimeComing = NULL;
}
}
#define TIME_KILL_SYNCHRONOUS 0x0100
void CCheckTick::SetPlayerTimer(int nMiniSeconds)
{
KillPlayerTimer();
UINT m_nwAccuracy = 1; //定时器精度参数
m_nPlayerTimerID = timeSetEvent(nMiniSeconds, m_nwAccuracy,
PlayerTimer, (DWORD)this, TIME_PERIODIC);
}
void CCheckTick::SetPlayerTimer()
{
this->SetPlayerTimer(40);
}
void CCheckTick::KillPlayerTimer()
{
if(m_nPlayerTimerID != -1)
{
ASSERT(m_nPlayerTimerID != -1);
timeKillEvent(m_nPlayerTimerID);
m_nPlayerTimerID = -1;
TRACE("timeKillEvent/n");
ASSERT(WaitForSingleObject(m_hTimeComing, 10000) == WAIT_OBJECT_0);
}
}
void CCheckTick::SetTickNotify(ITickNotify *pTickNotify)
{
m_pTickNotify = pTickNotify;
}
void CCheckTick::PlayerTimer(UINT wTimerID, UINT nMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
TRACE("ResetEvent/n");
ResetEvent(CCheckTick::m_hTimeComing);
CCheckTick *pCheckTick = (CCheckTick*)dwUser;
// TRACE("PlayerTimer/n");
ASSERT(pCheckTick != NULL);
ASSERT(pCheckTick->m_pTickNotify != NULL);
pCheckTick->m_pTickNotify->OnTickNotify();
SetEvent(CCheckTick::m_hTimeComing);
TRACE("SetEvent/n");
}
注意:如果无法等待回调线程结束,要看回调里是不是死锁了。如,在回调里引用UI线程中执行的函数,会
造成死锁,因为KillPlayerTimer一般被UI线程调用。