118 lines
3.3 KiB
C++
118 lines
3.3 KiB
C++
#include <limits.h>
|
||
#ifdef WIN32
|
||
#include <time.h>
|
||
#include <tchar.h>
|
||
#endif
|
||
#include "_osdef.h"
|
||
#include "Tick.h"
|
||
#include "Lock.h"
|
||
|
||
using namespace wylib::time::tick64;
|
||
static TICKCOUNT64 UserSetTick = 0;
|
||
|
||
#ifndef WIN32
|
||
unsigned int timeGetTime()
|
||
{
|
||
unsigned int uptime = 0;
|
||
struct timespec on;
|
||
if(clock_gettime(CLOCK_MONOTONIC, &on) == 0)
|
||
uptime = on.tv_sec*1000 + on.tv_nsec/1000000;
|
||
return uptime;
|
||
}
|
||
#endif
|
||
|
||
/***
|
||
实际测试的性能表明,基于timeGetTime实现的GetTickCount64具有较高的性能,
|
||
而基于QueryPerformanceCounter的实现则是timeGetTime版本时间消耗的300倍
|
||
***/
|
||
|
||
//static LONG dwAtomLock = 0;
|
||
#ifdef WIN32
|
||
static MMRESULT mmPeriod = timeBeginPeriod(1);
|
||
#endif
|
||
static TICKCOUNT64 llTickBase = 0;
|
||
static TICKCOUNT64 llStartTick = timeGetTime();
|
||
static DWORD dwLastShortTick = timeGetTime();
|
||
|
||
TICKCOUNT64 wylib::time::tick64::GetTickCount64()
|
||
{
|
||
if (UserSetTick)
|
||
return UserSetTick;
|
||
|
||
/*
|
||
此处需要将dwLastShortTick导致保存为局部变量并尝试通过保存的值以锁总线的方式改变dwLastShortTick的值。
|
||
由于在检测并修改dwLastShortTick的值的期间,当前线程可能由于进程调度而使得线程被挂起。当前线程被挂
|
||
起的期间如果其他线程也执行了此函数则该线程会先于此线程修改dwLastShortTick的值。当本线程在恢复后再修改
|
||
dwLastShortTick的值将导致错误的结果并会错误的判断为进入了一个49天的循环并修改llTickBase的值,从而导
|
||
致所有后续调用的返回值全部错误的问题!
|
||
为尽量降低数据同步的开销,不能使用临界区等方式来同步数据,故必须使用原子加锁操作指令代替。
|
||
*/
|
||
DWORD dwLastTick = dwLastShortTick;
|
||
DWORD dwTick = timeGetTime();
|
||
#ifdef WIN32
|
||
if (InterlockedCompareExchange((volatile long*)&dwLastShortTick, (long)dwTick, (long)dwLastTick) == dwLastTick)
|
||
#else
|
||
if (__sync_val_compare_and_swap((volatile long*)&dwLastShortTick, (long)dwLastTick, (long)dwTick) == dwLastTick)
|
||
#endif
|
||
{
|
||
if (dwTick < dwLastTick)
|
||
{
|
||
#ifdef WIN32
|
||
if (IsDebuggerPresent())
|
||
{
|
||
//请手动确认此处是否未发生BUG,而是系统真正的经过了49天的循环,并按继续键……
|
||
OutputDebugString(_T("请手动确认此处是否未发生BUG,而是系统真正的经过了49天的循环"));
|
||
DebugBreak();
|
||
}
|
||
llTickBase += 0x1UI64 << 32;
|
||
#else
|
||
llTickBase += 0x1LL << 32;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
return llTickBase + dwTick - llStartTick;
|
||
}
|
||
|
||
/*
|
||
TICKCOUNT64 wylib::time::tick64::GetTickCount64()
|
||
{
|
||
if (UserSetTick)
|
||
return UserSetTick;
|
||
|
||
static LARGE_INTEGER Frequency;
|
||
static BOOL boSuportPerformanceTick = QueryPerformanceFrequency(&Frequency);
|
||
|
||
LARGE_INTEGER tick;
|
||
TICKCOUNT64 sec, milpart;
|
||
|
||
if ( !boSuportPerformanceTick )
|
||
{
|
||
return timeGetTime();
|
||
}
|
||
|
||
QueryPerformanceCounter( &tick );
|
||
|
||
sec = tick.QuadPart / Frequency.QuadPart;
|
||
milpart = tick.QuadPart - (sec * Frequency.QuadPart);
|
||
return sec * 1000 + milpart * 1000 / Frequency.QuadPart;
|
||
}
|
||
*/
|
||
|
||
TICKCOUNT64 wylib::time::tick64::SetTickCount64(TICKCOUNT64 llValue)
|
||
{
|
||
//TICKCOUNT64 lOldTick = UserSetTick;
|
||
UserSetTick = llValue;
|
||
return UserSetTick;
|
||
}
|
||
|
||
TICKCOUNT32 wylib::time::tick64::GetTickCount32()
|
||
{
|
||
return timeGetTime();
|
||
}
|
||
|
||
TICKCOUNT32 wylib::time::tick64::SetTickCount32(TICKCOUNT32 dwTick)
|
||
{
|
||
return (TICKCOUNT32)SetTickCount64(dwTick);
|
||
}
|