我是否应该相信 std::thread 不是仅通过创建用户线程来实现的?

Should I just believe that std::thread is implemented not by creating user threads only?

我了解到,如果其中一个线程调用某些系统调用(例如 I/O 系统调用),所有与内核线程映射的用户线程都会被阻塞。

如果std::thread是在某些环境下只创建一个用户线程来实现的,那么在某些程序中I/O的线程可以阻塞渲染的线程。

所以我认为区分用户/内核很重要,但 C++ 标准并不重要。

那我怎么保证在特定的环境下(比如Windows10)不会出现上面的一些情况呢?

在与 OP 交谈并更好地理解真正被问到的内容之后,改写我的回答尝试。

大多数I/O操作在每个线程级别阻塞:如果一个线程启动一个,只有这个线程将被阻塞,不是整个过程。

OP 似乎打算在线程中启动渲染操作,不希望它被线程中的 I/O 操作阻塞。两种可能的解决方案是:

  1. 生成另一个线程来执行此阻塞 I/O 操作,然后让渲染线程独立于 I/O;
  2. 进行
  3. 要使用每个 OS(不属于 C++)的特定资源,以异步、非阻塞形式启动相同的 I/O 操作。
  4. 最后,为了尽量减少 OS 访问 I/O 的阻塞,应用程序开发人员可以做的是尝试确保不会同时访问相同的 I/O设备同时

您可以放心,std::thread 没有使用“用户线程”,因为该概念在世纪之交时几乎消失了。

现代硬件有多个 CPU 内核,如果有足够的内核线程,它们会工作得更好。如果没有足够的内核线程,CPU 个内核可能会闲置。

“用户线程”的想法起源于只有一个 CPU 内核的时代,人们反而担心内核线程太多。

I learned that all of user threads mapped with a kernel thread be blocked if one of the threads calls some system call likes I/O System Call.

是的,但是很少有任何东西直接使用内核的系统调用。通常他们使用 user-space 库。对于正常阻塞的“系统”调用(例如标准 C 库中的 read() 函数),库可以使用异步函数(例如标准 C 库中的 aio_read() 函数)和 user-space线程切换。

So I think distinguishing user / kernel is important but c++ standard does not.

这很重要,但出于不同的原因。

user-space线程的第一个问题是内核不知道线程的优先级。如果你想象一台计算机 运行ning 2 个完全独立的应用程序(用户使用“alt+tab”在它们之间切换),其中每个应用程序都有一个高优先级线程(用于用户界面),以及几个中优先级线程(用于一般工作)加上一些低优先级线程(用于在后台执行预取和 pre-calculating 之类的事情);您最终可能会遇到这样一种情况,即内核给一个应用程序 CPU 时间(低优先级线程使用 CPU 时间),因为它不知道另一个应用程序需要 CPU 时间用于其更高优先级的线程。

换句话说,对于 multi-process 环境,user-space 线程很可能会浪费 CPU 时间做不相关的工作(在一个进程中),而重要的工作(在另一个进程中)进程)等待。

user-space 线程的第二个问题是(对于现代系统)好的调度决策会考虑不同 CPU 之间的差异(“big.Little”,hyper-threading,哪些缓存由哪些 CPUs,..) 和电源管理(例如,对于低优先级线程,降低 CPU 时钟速度以增加电池寿命是合理的 and/or 减少 CPU 温度,因此当需要稍后完成更高优先级的工作时,它们可以 运行 更快更长时间); user-space 拥有 none 所需的信息(以及 none 改变 CPU 速度的能力等),无法做出良好的调度决策。

请注意,这些问题可以通过 user-space 和内核之间的大量通信来“修复”(user-space 线程通知内核等待线程的线程优先级,当前 运行ning 线程,内核通知 user-space CPU 差异和电源管理等);但是 user-space 线程切换的重点是避免内核系统调用的成本,因此 user-space 和内核之间的这种通信会使 user-space 线程切换毫无意义。

Then how I assure that some situations like above will not occur in particular environment(like Windows10 )?

你不能。这不是你的决定。

当您选择使用高级抽象(std::thread 在 C++ 中而不是直接从汇编语言中使用内核)时,您是在故意将低级决策委托给其他东西(编译器及其 run-time 环境)。优点(你不再需要关心这些决定)是缺点(你不再能够做出这些决定)。