【问题标题】:Calculating clock cycles in WINAPI gives very different results在 WINAPI 中计算时钟周期会得到非常不同的结果
【发布时间】:2014-06-12 10:42:46
【问题描述】:

我用于计算创建线程的时钟周期的代码是

# include <Windows.h>
# include <stdio.h>
# include <conio.h>

# define RUN 20000

DWORD WINAPI Calc(LPVOID Param){}

int main(int argc, char* agrv[])
{
    ULONG64 Sum = 0;

    for (int i = 0; i < RUN; i++)
    {
        ULONG64 ret = 0;
        DWORD ThreadId;
        HANDLE ThreadHandle;

        /* create the thread */
        ThreadHandle = CreateThread(
            NULL,           /* default security attributes */
            0,              /* default stack size */
            Calc,           /* thread function */
            NULL,           /* parameter to thread function */
            0,              /* default creation flags */
            &ThreadId);     /* returns the thread identifier */

        QueryThreadCycleTime(ThreadHandle, &ret);

        WaitForSingleObject(ThreadHandle, INFINITE);

        CloseHandle(ThreadHandle);

        Sum += ret;
    }

    printf_s("The Average no of cycles in %d runs is %lu\n", RUN, (DWORD)(Sum/RUN));

    _getch();
    return 0;
}

这段代码的结果是在我普通的笔记本电脑上大约 1000 个时钟周期。但是,如果我在 WaitForSingleObject 函数之后调用 QueryThreadCycleTime 函数,结果会非常不同,大约为 200,000。我环顾四周,但并没有真正找到解释。这种行为的原因是什么?

【问题讨论】:

  • 如果你计算完整的线程执行而不是只计算启动时间,你会得到一个更大的数字,为什么你会感到惊讶?

标签: c multithreading winapi


【解决方案1】:

区别在于是否等待线程完成执行。显然,如果您等待,那么这样做将允许线程使用更多时钟周期。

请注意,您没有对创建线程的过程进行计时。您正在计时线程过程的执行。让我明确一点,QueryThreadCycleTime 返回的值是执行线程所消耗的周期数,而不是执行 CreateThread 所花费的周期数,或者实际上是从调用 CreateThread 到线程启动所经过的挂钟时间执行。

而你这样做是在一个不确定的点上。例如,在您的代码中,QueryThreadCycleTime 有时会返回 0,因为在主线程调用 QueryThreadCycleTime 时线程甚至还没有开始执行。

如果您想计算线程创建时间,那么计算CreateThread 返回所需的时间。或者更好的是,测量从调用CreateThread 到线程开始执行之间的挂钟时间。

例如,代码可能如下所示:

# include <Windows.h>
# include <stdio.h>
# include <conio.h>

# define RUN 100000

DWORD WINAPI Calc(LPVOID Param){
    QueryPerformanceCounter((LARGE_INTEGER*)Param);
}

int main(int argc, char* agrv[])
{
    ULONG64 Sum = 0;

    for (int i = 0; i < RUN; i++)
    {
        LARGE_INTEGER PerformanceCountBeforeCreateThread, PerformanceCountWhenThreadStartsExecuting;
        DWORD ThreadId;
        HANDLE ThreadHandle;

        /* create the thread */
        QueryPerformanceCounter(&PerformanceCountBeforeCreateThread);
        ThreadHandle = CreateThread(NULL, 0, Calc,
            &PerformanceCountWhenThreadStartsExecuting, 0, &ThreadId);     
        WaitForSingleObject(ThreadHandle, INFINITE);
        CloseHandle(ThreadHandle);

        Sum += PerformanceCountWhenThreadStartsExecuting.QuadPart - PerformanceCountBeforeCreateThread.QuadPart;
    }

    printf_s("The Average no of counts in %d runs is %lu\n", RUN, (DWORD)(Sum/RUN));

    LARGE_INTEGER Frequency;
    QueryPerformanceFrequency(&Frequency);
    printf_s("Frequency %lu\n", Frequency.QuadPart);

    _getch();
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-08
    • 2020-04-09
    相关资源
    最近更新 更多