c - 使用 CreateThread() 时在 Windows 中获取线程创建的荒谬时间

标签 c windows multithreading

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

#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

创建一个进程的时间看起来很合理,但为什么创建一个线程比创建一个全新的进程要多一千倍呢?

最佳答案

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

  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. clock() 对于多线程程序来说是不准确的,正如@Some programmer dude 所指出的,相反,我们使用 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

关于c - 使用 CreateThread() 时在 Windows 中获取线程创建的荒谬时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58570454/

相关文章:

c++ - 是 char 空终止符是否包含在长度计数中

c - 在 C 中定义无参数函数 main() 的标准方法

c - 使用 MinGW 的 GCC 内联汇编加载 IDT 结构失败

c# - 从 linq 查询突出显示 ListView 中的文本

java - 非法线程状态异常

c - C : do we need to set unused thread to NULL? 中的多线程

C , fgets() 在尝试扫描字符串时扫描额外的字符

node.js - 如何在 Windows 上部署具有深度 node_modules 结构的 Node.js 应用程序?

c# - 如何在运行 exe 后关闭 cmd 窗口。从它的文件?

Java n 线程更新值