让我们假设我们有多线程应用程序必须在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
?
答案 0 :(得分:0)
您错误地假设内存中的所有字节都相似,即它们形成一个大池。这在Windows上完全不正确。
主要部门是分页池与非分页池。分页池存储可在必要时分页到磁盘的代码和数据。非分页池无法分页到磁盘。例如,处理分页的操作系统的基本部分无法分页到磁盘 - 您将如何将其重新分页?在这里,一个池可以是空的,而另一个池也有空间。
另一个有限的资源是用于物理和虚拟内存之间映射的RAM。显然,在您的所有流程中,您将会使用大量的流程。每个进程都有自己的地址空间。我们假设它是一个32位cl
进程;它有一百万页的4GB地址空间。您的60K进程共占用60亿个页面的地址空间。虽然这些页面中有相当一部分只是cl.exe
的共享副本,但每个页面都需要64位指向物理RAM的指针。
你在这里看到的有点有趣:你可以拥有60000 * 8 = 480.000字节的指向单个4096字节页面的指针。这种异常情况可能导致简单的内存统计数据更具误导性。如果你只计算4096字节的实际内容,你就会低估所需的内存大约100倍。