Windows 多线程强制执行线程优先级

Windows multi-threading enforcing thread priority

我期待发生的事情:

由于进程亲和性仅限于单核,因此当前进程的所有线程都必须竞争执行时间。

由于线程 a 的优先级高于线程 b 并且它从不阻塞,因此线程 b 永远不会被执行。

我所看到的:

线程 b 被误执行。

为什么会这样?有没有办法使用 WinAPI 强制执行此执行逻辑?

#include <iostream>
#include <thread>
#include <windows.h>

using namespace std;

DWORD WINAPI a_function(LPVOID lpParam)
{
    while (true) {
    }

    return 0;
}

DWORD WINAPI b_function(LPVOID lpParam)
{
    while (true) {
        cout << "b" << endl;
    }

    return 0;
}

int main()
{
    DWORD affinityMask = 1u;
    BOOL res = SetProcessAffinityMask(GetCurrentProcess(), affinityMask);
    if (!res) {
        return -1;
    }

    HANDLE a_handle = CreateThread(nullptr, 0, a_function, nullptr, CREATE_SUSPENDED, nullptr);
    HANDLE b_handle = CreateThread(nullptr, 0, b_function, nullptr, CREATE_SUSPENDED, nullptr);

    SetThreadPriority(a_handle, THREAD_PRIORITY_NORMAL);
    SetThreadPriority(b_handle, THREAD_PRIORITY_BELOW_NORMAL);

    ResumeThread(a_handle);
    ResumeThread(b_handle);

    WaitForSingleObject(a_handle, INFINITE);

    return 0;
}

输出:

b
b
b
b
b

注意:我没有使用 ResumeThread() / SuspendThread() 因为:

“SuspendThread 函数不适用于线程同步,因为它不控制代码中线程执行的暂停点。” (source)

优先级不是绝对的。只要您使用多线程,并且所有线程都处于 运行 可用状态(即,它们没有挂起或等待同步原语),它们 运行迟早。优先级仅确保具有更高优先级的线程以更少的延迟/更大的时间片进行调度,但不能确保它们在任何其他 class 线程获得机会之前被排他性地调度。

基本原理与您构建的非常相似:自旋锁。如果线程 a 是消费者,而线程 b 是生产者,那么 运行ning b 永远不会将 a 送入死锁。这个问题通常被称为 Priority Inversion,因为 b 在技术上比 a 优先,因为 a 正在等待 b , 但配置的优先级和不使用内核同步对象并不反映这种依赖性。

这不仅仅是一个假设的场景,而且实际上很常见。您可能会争辩说您不会在多线程系统上注意到,但理由再次是您不能仅仅通过将软件限制为单个 CPU 内核来冒险破坏软件,或者因为所有内核都得到被高优先级线程占用。