【问题标题】:Windows multi-threading enforcing thread priorityWindows 多线程强制线程优先级
【发布时间】:2021-09-15 17:10:01
【问题描述】:

我期望发生的事情:

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

由于线程 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)

【问题讨论】:

  • 您的系统是否只有一个核心?
  • @fredrik 不,但我将进程关联掩码设置为使用单核。
  • 由于线程 a 的优先级高于线程 b,并且它从不阻塞,因此线程 b 永远不会被执行。 不要认为这一定是真的。如何和展示你的测试
  • while (true) { } 在技术上是 UB - 检查生成的代码 - 它可能已被删除(无限循环,没有副作用)。如果发生这种情况,a_function 将立即返回。
  • 我认为这可能是我们看到的原因 - "...调度程序通过随机提高就绪线程的优先级来解决这个问题..." docs.microsoft.com/en-us/windows/win32/procthread/… 线程 B 正在得到提升,当 A 到达它的时间片线程的末尾时,B 因为它的优先级提升而开始运行。

标签: c++ windows multithreading winapi


【解决方案1】:

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

基本原理与您构建的内容非常相似:自旋锁。如果线程a 是消费者,线程b 是生产者,那么从不运行b 会使a 陷入死锁。该问题通常被称为优先级反转,因为b 在技术上将优先于a,因为a 正在等待b,但配置的优先级和未使用的内核同步对象不反映这种依赖关系。

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

【讨论】:

  • Priority inversion 是争用的结果。发布的代码中没有争用。线程不竞争共享资源。虽然读起来很合理,但我不相信这个提议的答案实际上是正确的。您是否使用“优先级反转”的更一般定义?
  • @IInspectable 问题的示例中没有优先级反转,但也无法向调度程序证明没有优先级反转(考虑到内核可见的原语)。因此,随机忽略优先级是调度程序可以采取的唯一措施来避免此类问题,从而导致观察到的效果。
猜你喜欢
  • 2011-06-25
  • 1970-01-01
  • 2012-11-17
  • 2016-06-03
  • 1970-01-01
  • 1970-01-01
  • 2014-11-26
  • 2010-09-22
  • 1970-01-01
相关资源
最近更新 更多