首页 > 解决方案 > 使用 CreateThread() 在 Windows 中创建线程的时间很荒谬

问题描述

因此,我创建了以下简单程序来测量在我的机器上创建进程或线程的平均时间:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> 
#include <unistd.h> 
#include <time.h>

DWORD WINAPI ThreadFunc(void* data) {

  return 0;
}

int main(int argc, char** argv) {

    STARTUPINFO si = {0};
    PROCESS_INFORMATION pi = {0};
    clock_t begin, end;
    double cpu_time_used;

    for(int i = 0; i <= 1000000;i++){
        begin = clock();
        CreateProcess(NULL, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
        end = clock();
        cpu_time_used += ((double) (end - begin)) / CLOCKS_PER_SEC;
        TerminateProcess(pi.hProcess, 0);
    }
    /* since we're running 1 000 000 (1 million) times we divide by 1 
     * million and since to get the time in ns instead of ns we multiply by
     * 1 billion we simply multiply by 1000 since 1 billion / 1 million = 1000.
     */
    printf("Average time to create a process = %f ns\n", cpu_time_used * 1000); 

    cpu_time_used = 0;

    for(int i = 0; i < 1000000;i++){
        begin = clock();
        CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
        end = clock();
        cpu_time_used += ((double) (end - begin)) / CLOCKS_PER_SEC;
    }
    /* since we're running 1 000 000 (1 million) times we divide by 1 
     * million and since to get the time in ns instead of ns we multiply by
     * 1 billion we simply multiply by 1000 since 1 billion / 1 million = 1000.
     */
    printf("Average time to create a Thread = %f ns\n", cpu_time_used * 1000);
    return (EXIT_SUCCESS);
}

以下结果:

Average time to create a process = 89.000000 ns
Average time to create a Thread = 112055.000000 ns

创建一个进程的时间似乎很合理,但为什么创建一个线程的时间比创建一个全新的进程要长一千倍呢?

标签: cwindowsmultithreading

解决方案


好的,我的方法有几个错误,我将在这里解释,最后附上完整的最终代码。

  1. CreateProcess() 调用什么都不做,而不是启动一个什么都不做的程序。为了解决这个问题,我们CreateProcess(NULL, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);更改CreateProcess("C:\\Windows\\System32\\rundll32.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);并暂停该过程。
  2. Windows 将程序限制为 2048 个线程。这意味着在第 2048 个线程之后发生了一个额外的瓶颈,因为程序等待线程关闭以打开一个新线程。为了避免这种情况,我将循环减少到只有 1000 个。
  3. 正如@Some程序员老兄指出的那样,clock() 对于多线程程序是不准确的,相反,我们使用 QueryPerformanceCounter()。请记住,根据您的 IDE 和其他因素,QueryPerformanceFrequency 可能会错误地返回 10 MHz(NetBeans 有此问题,因此更改为 Visual Studio),因此请先进行测试。

固定的最终代码是:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> 

#include <time.h>

DWORD WINAPI ThreadFunc(void* data) {

    return 0;
}

int main(int argc, char** argv) {

    STARTUPINFO si = { 0 };
    PROCESS_INFORMATION pi = { 0 };

    LARGE_INTEGER begin, end, cpu_time_used;
    LARGE_INTEGER Frequency;
    cpu_time_used.QuadPart = 0;

    QueryPerformanceFrequency(&Frequency);


    for (int i = 0; i <= 1000; i++) {
        QueryPerformanceCounter(&begin);
        CreateProcess("C:\\Windows\\System32\\rundll32.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
        QueryPerformanceCounter(&end);
        cpu_time_used.QuadPart += end.QuadPart - begin.QuadPart;
        TerminateProcess(pi.hProcess, 0);
    }
    cpu_time_used.QuadPart *= 1000000;
    cpu_time_used.QuadPart /= Frequency.QuadPart;

    printf("Average time to create a process = %lld us\n", cpu_time_used.QuadPart / 1000);

    cpu_time_used.QuadPart = 0;
    HANDLE hThread;
    for (int i = 0; i <= 1000; i++) {
        QueryPerformanceCounter(&begin);
        hThread = CreateThread(NULL, 0, ThreadFunc, NULL, CREATE_SUSPENDED, NULL);
        QueryPerformanceCounter(&end);
        cpu_time_used.QuadPart += end.QuadPart - begin.QuadPart;
    }
    cpu_time_used.QuadPart *= 1000000;
    cpu_time_used.QuadPart /= Frequency.QuadPart;

    printf("Average time to create a Thread = %lld us\n", cpu_time_used.QuadPart / 1000);
    return (EXIT_SUCCESS);
}

返回:

Average time to create a process = 8289 us
Average time to create a Thread = 26 us

推荐阅读