“CreateProcess”真的是线程安全吗?

时间:2017-11-24 16:29:26

标签: c++ multithreading winapi

让我们假设我们有多线程应用程序必须在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应该是线程安全的,是否有更有效的方法在多线程应用程序中创建子进程,使用mutex只在单线程上调用CreateProcess

1 个答案:

答案 0 :(得分:0)

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

主要部门是分页池与非分页池。分页池存储可在必要时分页到磁盘的代码和数据。非分页池无法分页到磁盘。例如,处理分页的操作系统的基本部分无法分页到磁盘 - 您将如何将其重新分页?在这里,一个池可以是空的,而另一个池也有空间。

另一个有限的资源是用于物理和虚拟内存之间映射的RAM。显然,在您的所有流程中,您将会使用大量的流程。每个进程都有自己的地址空间。我们假设它是一个32位cl进程;它有一百万页的4GB地址空间。您的60K进程共占用60亿个​​页面的地址空间。虽然这些页面中有相当一部分只是cl.exe的共享副本,但每个页面都需要64位指向物理RAM的指针。

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