UDP服务器给客户发数据的过程中需要延时,我就加了Sleep(1);,结果这个循环1秒钟只执行60次左右,以下是测试程序段:
CTime g_timeBegin;
CTime g_timeEnd;
bool g_blnRunThread=false;
int g_iTimes=0;
UINT TestSleepThread(LPVOID lParam)
{
g_iTimes=0;
g_timeBegin=CTime::GetCurrentTime();
CTestSleepDlg *pDlg=(CTestSleepDlg *)lParam;
while(g_blnRunThread)
{
g_iTimes++;
Sleep(10);
}
AfxEndThread(0);
return 0;
}
void CTestSleepDlg::OnButton1() 
{
if(g_blnRunThread)
{
AfxMessageBox("已经开始了!");
return;
}
HANDLE pThread=NULL;
DWORD dwThreadID;
g_blnRunThread=true;
pThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)TestSleepThread,this,THREAD_PRIORITY_NORMAL,&dwThreadID);
if(pThread==NULL)
{
g_blnRunThread=false;
DWORD dwError=GetLastError();
TRACE1("\nerror beginThread:Error%d",dwError);
AfxMessageBox("初始化出错!程序退出");
CDialog::OnOK();
}
}void CTestSleepDlg::OnButton2() 
{
g_blnRunThread=false;
g_timeEnd=CTime::GetCurrentTime();
m_csMsg.Format("次数:%d 时间:%d秒",g_iTimes,g_timeEnd-g_timeBegin);
UpdateData(FALSE);
}
Button2点击后,发现平均下来每秒钟只有60次左右,奇怪?如何提高能力?

解决方案 »

  1.   

    Sleep以及Timer消息等最多只能达到30毫秒左右的精度,因为毕竟不是实时操作系统,不过据说winCE可以达到1毫秒的精度
      

  2.   

    其实改成Sleep(1)结果也是一样的。
      

  3.   

    不过最后还是搞定了,使用的是WaitForSingleObject,这个快,也不占CPU时间
    如下修改:
    UINT TestSleepThread(LPVOID lParam)
    {
    g_iTimes=0;
    g_timeBegin=CTime::GetCurrentTime();
    CTestSleepDlg *pDlg=(CTestSleepDlg *)lParam;
    HANDLE event;//***********
    event=CreateEvent(NULL,TRUE,FALSE,"TEST");//***********
    if(event==NULL)
    {
    ASSERT(FALSE);
    g_blnRunThread=false;
    AfxEndThread(0);
    return 0;
    }
    while(g_blnRunThread)
    {
    g_iTimes++;
    WaitForSingleObject(event,1);//***********
    ResetEvent(event);//***********
    }
    AfxEndThread(0);
    return 0;
    }
    现在是1ms时大概会有600次了,快多了
      

  4.   

    或者你也可以用SOCKET 的SELECT函数,这可以精确到微秒级!! Sleep()和timer精确度也是10+ 毫秒级的
      

  5.   

    To  Practise_Think(时代“过客”) :
    SELECT怎么个用法?没用过To  mousubin(msb) :
    你的机器上Sleep(1)的情况下,可以每秒钟循环多少次?
      

  6.   

    Sleep() Timer等的精度是55毫秒
      

  7.   

    Settimer精度是50ms左右。更精确的计时可以用多媒体计时器。要更精确的话可以读CPU的时间片。
      

  8.   

    一.高精度延时, 是 CPU 测速的基础
    Windows 内部有一个精度非常高的定时器, 精度在微秒级, 但不同的系统这个定时器的频率不同, 这个频率与硬件和操作系统都可能有关。利用 API 函数 QueryPerformanceFrequency 可以得到这个定时器的频率。
    利用 API 函数 QueryPerformanceCounter 可以得到定时器的当前值。
    根据要延时的时间和定时器的频率, 可以算出要延时的时间定时器经过的周期数。
    在循环里用 QueryPerformanceCounter 不停的读出定时器值, 一直到经过了指定周期数再结束循环, 就达到了高精度延时的目的。高精度延时的程序, 参数: 微秒:void DelayUs(__int64 Us)
    {
        LARGE_INTEGER CurrTicks, TicksCount;     QueryPerformanceFrequency(&TicksCount);
        QueryPerformanceCounter(&CurrTicks);     TicksCount.QuadPart = TicksCount.QuadPart * Us / 1000000i64;
        TicksCount.QuadPart += CurrTicks.QuadPart;     while(CurrTicks.QuadPart<TicksCount.QuadPart)
            QueryPerformanceCounter(&CurrTicks);
    } 二.测速程序
    利用 rdtsc 汇编指令可以得到 CPU 内部定时器的值, 每经过一个 CPU 周期, 这个定时器就加一。
    如果在一段时间内数得 CPU 的周期数, CPU工作频率 = 周期数 / 时间为了不让其他进程和线程打扰, 必需要设置最高的优先级
    以下函数设置当前进程和线程到最高的优先级。 
    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); CPU 测速程序的源代码, 这个程序通过 CPU 在 1/16 秒的时间内经过的周期数计算出工作频率, 单位 MHz: int CPU_Frequency(void) //MHz
    {
        LARGE_INTEGER CurrTicks, TicksCount;
        __int64 iStartCounter, iStopCounter;    DWORD dwOldProcessP = GetPriorityClass(GetCurrentProcess());
        DWORD dwOldThreadP = GetThreadPriority(GetCurrentThread());    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
        SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);    QueryPerformanceFrequency(&TicksCount);
        QueryPerformanceCounter(&CurrTicks);    TicksCount.QuadPart /= 16;
        TicksCount.QuadPart += CurrTicks.QuadPart;    asm rdtsc
        asm mov DWORD PTR iStartCounter, EAX
        asm mov DWORD PTR (iStartCounter+4), EDX    while(CurrTicks.QuadPart<TicksCount.QuadPart)
            QueryPerformanceCounter(&CurrTicks);    asm rdtsc
        asm mov DWORD PTR iStopCounter, EAX
        asm mov DWORD PTR (iStopCounter + 4), EDX    SetThreadPriority(GetCurrentThread(), dwOldThreadP);
        SetPriorityClass(GetCurrentProcess(), dwOldProcessP);    return (int)((iStopCounter-iStartCounter)/62500);
    }
     前面是用 API 函数进行延时, 如果知道了 CPU 的工作频率, 利用循环, 也可以得到高精度的延时int _CPU_FREQ = 0; //定义一个全局变量保存 CPU 频率 (MHz)void CpuDelayUs(__int64 Us) //利用循环和 CPU 的频率延时, 参数: 微秒
    {
        __int64 iCounter, iStopCounter;    asm rdtsc
        asm mov DWORD PTR iCounter, EAX
        asm mov DWORD PTR (iCounter+4), EDX    iStopCounter = iCounter + Us*_CPU_FREQ;    while(iStopCounter-iCounter>0)
        {
            asm rdtsc
            asm mov DWORD PTR iCounter, EAX
            asm mov DWORD PTR (iCounter+4), EDX
        }
    }void TestDelay(void)

        _CPU_FREQ = CPU_Frequency(); //利用 CPU 频率初始化定时
        CpuDelayUs(1000000); //延时 1 秒钟

     总结:
    无论是前面程序中的 DelayUs 函数还是 CpuDelayUs 函数, 实际上的基础都是 API 函数 QueryPerformanceCounter
    如果认为精度不够, 可以在测试 CPU 频率时延时更长时间, 但经过我的测试, 1/16秒足够了, 可以较高精度的测出 CPU 的工作频率。
    程序里要进行高精度(微秒级)的延时, 完全可以采用 DelayUs 和 CpuDelayUs 函数。
      

  9.   

    To rabo(不哭死人) :可惜DelayUs的CPU占用率是100%,不适合UDP数据发送时使用。
      

  10.   

    Sleep() Timer等的精度是55毫秒
      

  11.   

    感觉应该比55ms少一些似的。前面的程序中我得到的结果大概是 60次/秒,也就是说好象是15ms级别的
      

  12.   

    奇怪,刚试了一下WaitForSingleObject居然也不行了,难道是我以前眼花了吗?
      

  13.   

    Sleep() Timer等的精度与操作系统有关,nt 为18秒左右,其他是55毫秒.
      

  14.   

    to zoulijun() 占用100%,你不是要微秒或毫秒级的延时吗?又不是要延几分种,要延几分种你就用Sleep吧。再说你可以新开线程来延时,如果还是觉得占资源,就用多媒体定时器吧。
      

  15.   

    这个延时主要是用在UDP发送数据过程中的。每发送一次就要延时一次,但是如果此时CPU占用率太高,就没法做别的事了。看来多媒体定时器是最后的选择?