【问题标题】:Proper use of threads Win32正确使用线程 Win32
【发布时间】:2015-10-03 07:40:23
【问题描述】:

我刚刚学习了 Win32 编程并且有一个关于线程的问题。假设我有下面的示例,我想知道在 for 循环中调用的 PrintStuff() 函数是在创建的新线程上运行还是在主线程上运行?谢谢。

    HANDLE hThrd;
    DWORD WINAPI PrintStuff() {
        OutputDebugString("printing stuff");
        return 0;
    }
    int WINAPI WinMain(...) {
        ...
        hThrd = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PrintStuff, NULL, CREATE_SUSPENDED, &id)
        int i;
        for (i = 0; i < 5; i++) {
            PrintStuff();
        }
        ...
    }

【问题讨论】:

  • for 循环中的 PrintStuff() 在原始线程中运行。 PrintStuff() 也将在您的新线程中运行...如果/当您启动该新线程时(在创建它之后)。

标签: c++ multithreading


【解决方案1】:

您似乎认为CreateThread 以某种方式“标记”了要在另一个线程中运行的函数,因此每次调用它都会在另一个线程中运行。不像那样。 CreateThread,顾名思义,只是创建一个新线程,其入口点是您指定的函数。调用之后的所有指令仍然像以前一样在同一个线程中运行,而您指定的函数将在调用CreateThread 后的几分钟内在单独的线程中调用一次。

顺便说一句,如果您要在新创建的线程上使用标准库中的任何函数,则不应直接使用CreateThread,而应使用_beginthread


我现在看到您指定了CREATE_SUSPENDED 标志;因此,除非您在其上调用ResumeThread,否则新线程将永远不会运行。

【讨论】:

    【解决方案2】:

    有多种方法可以确定哪个线程正在运行该函数。

    1。获取当前线程ID

    GetCurrentThreadId() 可以与 Windows API 一起使用。

    C++ 中还有许多其他方法。 C++ 标准库还在#include &lt;thread&gt; 中提供了std::this_thread::get_id(),可用于获取ID 以独立于平台的方式进行比较。

    使用线程 ID,您可以简单地在 WinMain 开始时检查线程 ID,并将主线程的 ID 存储在全局变量中,您可以在 PrintStuff 中使用。

    请注意,标准库 get_id() 返回的 ID 集与 GetCurrentThreadId() 不同,因此您需要选择一个。

    2。使用线程局部变量。

    在带有 Visual Studio 的 Windows 平台上,您可以使用 __declspec(thread)。如果你有 C++14(Visual Studio 2015 可用),你可以使用thread_local

    使用线程局部变量,您可以轻松判断主线程是否正在运行该函数。

    __declspec(thread) bool isMainThread = false;
    HANDLE hThrd;
    DWORD WINAPI PrintStuff() {
        OutputDebugString("printing stuff");
        // check isMainThread here
        return 0;
    }
    int WINAPI WinMain(...) {
        isMainThread = true;
        ...
        hThrd = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PrintStuff, NULL, CREATE_SUSPENDED, &id)
        int i;
        for (i = 0; i < 5; i++) {
            PrintStuff();
        }
        ...
    }
    

    线程局部变量可用于存储线程名称,而不是仅仅打印不容易解释的线程 ID。

    3。将参数传递给函数,或使用包装函数

    如果你只是想打印一些不同的东西,你可以在创建一个新线程时使用一个包装函数,并让这个函数将一个参数传递给你的 PrintStuff 函数。如果您不想将参数传递给 PrintStuff 以执行不同的操作,您还可以使用包装函数来设置线程局部变量。您可以在此处为线程命名。

    【讨论】:

      【解决方案3】:

      您可以打印 threadId 以查看使用的线程。

      https://msdn.microsoft.com/en-us/library/windows/desktop/ms683183(v=vs.85).aspx

      如果要检查是否在主线程中打印,可以获取上面函数中使用的主threadId,并与PrintStuff中的threadId进行比较。

      【讨论】:

        【解决方案4】:

        使用函数中的GetCurrentThreadId() 来了解当前正在执行它的线程。

        DWORD WINAPI PrintStuff() {
            DWORD idThread = GetCurrentThreadId();
            printf("Thread ID: %i.\n", idThread);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-05
          • 2021-01-02
          • 1970-01-01
          相关资源
          最近更新 更多