Windows上使用std::thread对XP SP2有兼容问题,调用了系统API:GetLogicalProcessorInformation
可以使用boost::thread解决,boost::thread编译需加上支持XP宏定义
b2 release define=BOOST_USE_WINAPI_VERSION=BOOST_WINAPI_VERSION_WINXP
boost has dropped winxp support by default. However, it does offer option to allow binary to run on winxp.
We followed the options on http://www.boost.org/users/history/version_1_60_0.html , and the compiled binaries can run on winxp sp3. Sadly, not including winxp sp2.Let’s take a look at the build instruction:
This release of Boost will by default compile for Windows Vista/Windows Server 2008, if the compiler supports a recent enough Windows SDK, and for Windows XP otherwise. Binaries compiled with default options may not run on the older Windows versions.
It is still possible to explicitly specify target Windows version by defining BOOST_USE_WINAPI_VERSION to a numeric version of Windows API. For example, building Boost for Windows XP can be done with the following command:
b2 release define=BOOST_USE_WINAPI_VERSION=0x0501
But the compiled binaries will get following error when running on winxp sp2.
The procedure entry point GetLogicalProcessorInformation could not be located in the dynamic link library KERNEL32.dll.
Use IDA to disassemble the binary, we can see it’s due to boost::thread::hardware_concurrency()
Here is its implement:unsigned thread::physical_concurrency() BOOST_NOEXCEPT
{
// a bit too strict: Windows XP with SP3 would be sufficient
#if BOOST_PLAT_WINDOWS_RUNTIME \
|| ( BOOST_USE_WINAPI_VERSION <= BOOST_WINAPI_VERSION_WINXP ) \
|| ( ( defined(__MINGW32__) && !defined(__MINGW64__) ) && _WIN32_WINNT < 0x0600)
return 0;
#else
unsigned cores = 0;
DWORD size = 0;GetLogicalProcessorInformation(NULL, &size);
if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
return 0;std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(size);
if (GetLogicalProcessorInformation(&buffer.front(), &size) == FALSE)
return 0;const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
for (size_t i = 0; i < Elements; ++i) {
if (buffer[i].Relationship == RelationProcessorCore)
++cores;
}
return cores;
#endif
}
if we put #pragma message in front of if-conditional statement, BOOST_USE_WINAPI_VERSION = 0x0501 while BOOST_WINAPI_VERSION_WINXP is BOOST_WINAPI_VERSION_WINXP, a bit wired.
So the solution is
define=BOOST_USE_WINAPI_VERSION=BOOST_WINAPI_VERSION_WINXP
instead of the suggestion from boost official website:
define=BOOST_USE_WINAPI_VERSION=0x0501
Verified with IDA:
.text$mn:0000106C ; unsigned int __cdecl boost::thread::physical_concurrency()
.text$mn:0000106C public ?physical_concurrency@thread@boost@@SAIXZ
.text$mn:0000106C ?physical_concurrency@thread@boost@@SAIXZ proc near
.text$mn:0000106C push ebp
.text$mn:0000106D mov ebp, esp
.text$mn:0000106F xor eax, eax
.text$mn:00001071 pop ebp
.text$mn:00001072 retn
.text$mn:00001072 ?physical_concurrency@thread@boost@@SAIXZ endpIt has become an empty function. The problem has been solved!