【问题标题】:Is `CreateProcess` really thread safe?`CreateProcess` 真的是线程安全的吗?
【发布时间】:2017-11-24 16:29:25
【问题描述】:

假设我们有一个多线程应用程序,它必须在 Windows 上运行一些外部可执行文件。最好的例子是 Apache 在多个线程上调用 CGI 脚本。

CreateProcess 文档不包含有关其使用限制的任何信息。所以,它应该是线程安全的。

让我们创建将使用CreateProcess 在多个线程中运行cl.exe 命令的程序。程序所做的唯一工作是创建 100 个线程,每个线程运行 cl.exe 并休眠 1 秒。我运行这个程序 10 分钟,所以它运行 cl.exe 600 * 100 = 60000 次。通常cl.exe 运行良好,但是,25 次 CreateProcess 返回 0 和 GetLastError 返回 8。来自 Microsoft,8 = ERROR_NOT_ENOUGH_MEMORY。这是不可能的,因为我的系统有 24 GB 的内存并且只使用了 40% 的内存。所以,错误看起来是错误的。

好的,现在我在 1000 个线程上运行相同的进程,现在几乎所有的CreateProcess 调用都会导致假的ERROR_NOT_ENOUGH_MEMORY

如果我们确保在每个时刻都在单线程中调用CreateProcess,这个问题就会消失(我使用std::mutex)。

有谁知道CreateProcess 应该是线程安全的,有没有更有效的方法在多线程应用程序中创建子进程,只使用互斥锁在单线程上调用CreateProcess

【问题讨论】:

  • CreateProcess 是线程安全的。您正在运行 32 位应用程序吗?或者,如果您重击系统,可能会耗尽许多其他资源。除非你有 大量 数量的核心产生这么多的 cl,否则会适得其反。
  • 这也可能有助于解释您可能会在许多线程或进程中看到的一些问题。 blogs.technet.microsoft.com/markrussinovich/2009/07/05/…
  • 不正确。线程安全 相同,因为我可以运行大量线程并且它必须工作。我没有问你的操作系统,我问的是你的应用程序。你的应用程序是什么位? 32 还是 64?
  • 每件事都有限制,而您的使用模式正在达到其中的一个或多个。这不仅仅是物理内存。

标签: c++ multithreading winapi


【解决方案1】:

您错误地假设内存中的所有字节都是相似的,即它们形成一个大池。这在 Windows 上是完全不正确的。

主要划分是分页池与非分页池。分页池存储可以在必要时分页到磁盘的代码和数据。非分页池不能分页到磁盘。例如,处理分页的操作系统的重要部分不能分页到磁盘——你将如何将它们分页?在这里,一个池可以是空的,而另一个池仍有空间。

另一个有限的资源是用于物理和虚拟内存之间映射的 RAM。显然,在您的所有流程中,您将使用其中的很多。每个进程都有自己的地址空间。假设它是一个 32 位的cl 进程;它有 4GB 的地址空间,以一百万页的形式存在。您的 60K 进程总共占用了 600 亿 页的地址空间。虽然其中不少页面只是cl.exe 的共享副本,但这些页面中的每一个都需要一个指向物理 RAM 的 64 位指针。

你在这里看到的有点有趣:你可以有 60000*8 = 480.000 字节的指针指向一个 4096 字节的页面。这是一种不寻常的情况,可能会导致简单的内存统计数据具有额外的误导性。如果您只计算 4096 字节的实际内容,您就会低估所需的内存大约 100 倍。

【讨论】:

  • 它是否解释了系统在 55% 的可用内存时内存不足?其次,你没有看我写的;没有人并行运行 60K 进程。最多 1000 个60K 是这样的程序在一分钟内将创建多少;程序每秒运行进程并等待其退出。即使我有 100 个进程并行运行,也会出现内存不足。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
相关资源
最近更新 更多