Microsoft 确实改变了InitializeCriticalSection
在 Vista、Windows Server 2008 和可能还有 Windows 7 上的工作方式。
他们添加了一个“功能”,以便在分配一堆 CS 时保留一些用于调试信息的内存。您分配的越多,保留的内存就越多。它可能是渐近的并最终变平(没有完全购买这个)。
为了避免这个“特性”,你必须使用新的 API InitalizeCriticalSectionEx并传递 flag CRITICAL_SECTION_NO_DEBUG_INFO
。
这样做的好处是它可能会更快,因为通常只使用旋转计数而无需实际等待。
缺点是您的旧应用程序可能不兼容,您需要更改您的代码,并且它现在依赖于平台(您必须检查版本以确定使用哪个版本)。如果需要,您也会失去调试能力。
冻结 Windows Server 2008 的测试工具包:
- 将此 C++ 示例构建为 CSTest.exe
#include "stdafx.h"
#include "windows.h"
#include <iostream>
using namespace std;
void TestCriticalSections()
{
const unsigned int CS_MAX = 5000000;
CRITICAL_SECTION* csArray = new CRITICAL_SECTION[CS_MAX];
for (unsigned int i = 0; i < CS_MAX; ++i)
InitializeCriticalSection(&csArray[i]);
for (unsigned int i = 0; i < CS_MAX; ++i)
EnterCriticalSection(&csArray[i]);
for (unsigned int i = 0; i < CS_MAX; ++i)
LeaveCriticalSection(&csArray[i]);
for (unsigned int i = 0; i < CS_MAX; ++i)
DeleteCriticalSection(&csArray[i]);
delete [] csArray;
}
int _tmain(int argc, _TCHAR* argv[])
{
TestCriticalSections();
cout << "just hanging around...";
cin.get();
return 0;
}
-...运行这个批处理文件(需要来自服务器 SDK 的 sleep.exe)
@rem you may adapt the sleep delay depending on speed and # of CPUs
@rem sleep 2 on a duo-core 4GB. sleep 1 on a 4CPU 8GB.
@for /L %%i in (1,1,300) do @echo %%i & @start /min CSTest.exe & @sleep 1
@echo still alive?
@pause
@taskkill /im cstest.* /f
-...在启动 300 个实例之前看到一个 8GB 和四核 CPU 的 Win2008 服务器冻结。
-...在 Windows 2003 服务器上重复,看看它处理它就像一个魅力。