c++ - 当 CPU 内核可用时,什么会导致 Windows 调度程序忽略高优先级线程?
问题描述
我有一个多线程应用程序,其中一个线程具有时间关键的工作。此时间关键线程在启动时设置为“时间关键”优先级。此外,应用程序中的其他线程具有处理器关联掩码集,因此这个时间关键线程始终可以完全访问八个 CPU 内核(两个 Xeon 共 12 个内核)。服务器上没有运行其他应用程序(除了 Windows 自己运行的任何服务)。
尽管如此,即使采取了所有这些预防措施,我也会记录这个时间关键线程一次没有运行 80-100 毫秒的事件。我的日志显示它有时会在任务中停止,并在 80-100 毫秒的时间间隔后再次恢复。
我的问题是:什么可能导致这些 80-100 毫秒的线程中断和/或我如何找出导致它们的原因?
其他一些可能相关的信息:
- 停电与其他应用程序线程上的大量活动密切相关,但我正在监控资源监视器中的 CPU 使用率图表,可以看到专用于时间关键任务的 CPU 远低于 100%(但 4 个已满在此期间访问通常是 100%)
- 在这些往往会发生停电的峰值性能期间,也有大量的网络活动。
- 时间紧迫的任务是通过 PCIe 通信与硬件进行交互,但与此设备通信时不一定会发生“中断”事件。
- 当一切正常时,时间关键线程只花费大约 1-2 毫秒的时间来完成工作,然后在繁忙的循环中等待大约 30 毫秒。
- 时间关键任务确实与其他一些线程共享资源,但它受到自旋锁的保护,并且日志记录表明在等待锁定时没有发生中断。此外,我可以看到这些其他线程没有保持自旋锁超过几微秒。
- 通过任务管理器将应用程序优先级更改为“高”不会提高性能
- 我有运行 Win7 和 Win10 的测试服务器,都显示了问题。
解决方案
在过去的几天里,我进行了一些测试,并且能够收集到一些有趣的数据,我将在下面进行总结。
- 当 CPU 大部分空闲时,这个问题几乎不会发生
- 我可以很容易地通过从另一个简单地使用许多线程消耗它的进程中爆破 CPU 来导致失败
- 我认为我可以通过进程关联掩码限制大多数线程并将时间关键线程留在它们自己的专用 CPU 上来减少问题。然而,事实证明这不是一个完整的解决方案,因为存在一些导致争用问题的共享锁(用于传递信息和日志工具)。短暂持有关键锁的高争用但低优先级线程将在持有锁时进入睡眠状态,让我的高优先级线程(在空闲 CPU 上,请注意)等待。
- 到目前为止,我运行的最有趣的测试是采用一个故障率很高的特定 Windows 7 测试系统,我在相同的硬件上安装了一个全新的 Windows 10 副本并运行完全相同的软件。在完全相同的操作条件下,这极大地降低了故障率。
最终,我认为问题归结为 Windows 没有很好地处理 1) 线程优先级,一般和 2) 优先级反转问题尤其如此。令人惊讶的是,Windows 10 似乎比 Windows 7 能更好地处理这些问题。
微软有一篇关于操作系统如何处理优先级反转的简短文章,但似乎当 CPU 被多个线程重载时,这种策略似乎不足以防止关键线程的长时间延迟,尤其是在 Windows 7 中。
推荐阅读
- python - 在列表中搜索多个项目
- sql-server - SQL Server - 按升序排序似乎不起作用
- swift - 为什么我在 swift 上的视图是这样的 我更新了它,现在我能够向下滑动并能够返回到最后一页 XCODE 11
- google-apps-script - 连续运行 Apps 脚本函数
- java - 领域结果返回 null
- typescript - 是否可以设置函数的泛型类型而不在 Typescript 中调用它?
- javascript - 在折线图中创建圆角 [vue-chart.js]
- sql - Oracle - 如何根据某个值更改字段值
- docker - 在 Raku 中通过 NativeCall 调用 GSL 函数会引发错误
- javascript - selenium如何运行一个javascript函数