在Windows 10 x64上使用Visual Studio 2019 Professional。我有几个C ++ DLL项目,其中一些是多线程的。我将CRITICAL_SECTION
对象用于线程安全。
在DLL1中:
CRITICAL_SECTION critDLL1;
InitializeCriticalSection(&critDLL1);
在DLL2中:
CRITICAL_SECTION critDLL2;
InitializeCriticalSection(&critDLL2);
当我将critDLL1与EnterCriticalSection
或一起使用时,LeaveCriticalSection
在_DEBUG
或NDEBUG
模式下一切都很好。但是,当我使用critDLL2时,我的“ ntdll.dll”中存在访问冲突NDEBUG
(尽管不是_DEBUG
)。
在NDEBUG
模式下弹出消息框后,我终于能够跟踪到第一次使用的问题EnterCriticalSection
。
是什么导致该CRITICAL_SECTION
项目在一个项目中失败而在其他项目中起作用?在MSDN页面是没有帮助的。
更新1
比较DLL1(有效)和DLL2(无效)的项目设置后,我不小心使DLL2正常工作。我已通过还原到早期版本(崩溃)并进行项目更改(没有崩溃!)来确认这一点。
这是设置:
Project Properties > C/C++ > Optimization > Whole Program Optimization
将此设置为Yes (/GL)
,我的程序崩溃。将其更改为No
,它可以正常工作。什么是/GL
开关做和为什么它可能导致这个崩溃?
更新2
@Acorn的出色回答和@RaymondChen的评论提供了线索,以查找并解决问题。有两个问题(都是程序员错误)。
问题1
Whole Program Optimzation
(wPO)的假设是MSVC编译器正在编译“整个程序”。对于我的DLL项目,这是一个不正确的假设,该DLL项目在内部使用第3方库,然后由用Delphi编写的外部应用程序使用。此设置Yes (/GL)
默认设置为,但应为No
。这感觉像是Visual Studio中的错误,但是无论如何,程序员都需要意识到这一点。我不知道该怎么做的所有细节WPO
,但是至少对于要由其他应用程序使用的DLL,应该更改默认值。
问题2
严重的程序员错误。这是对第3方库的调用,该库返回了128字节的ASCII码,这是错误的:
// Before
// m_config::acSerial defined as "char acSerial[21]"
(void) m_pLib->GetPara(XPARA_PRODUCT_INFO, &m_config.acSerial[0]);
EnterCriticalSection(&crit); // Crash!
// After
#define SERIAL_LEN 20
// m_config::acSerial defined as "char acSerial[SERIAL_LEN+1]"
//...
char acSerial[128];
(void) m_pLib->GetPara(XPARA_PRODUCT_INFO, &acSerial[0]);
strncpy(m_config.acSerial, acSerial, max(SERIAL_LEN, strlen(acSerial)));
EnterCriticalSection(&crit); // Works!
现在很明显的错误是,第三方库没有将设备的序列号复制到char*
我提供的设备中...而是将128个字节复制到了我char*
对内存中所有连续的东西的踩踏中acSerial
。之前没有注意到这一点,因为这是m_pLib->GetPara(XPARA_PRODUCT_INFO, ...)
第3方库中的第一个调用,而在那一点上其余的连续数据大多为NULL。
问题从来都不与CRITICAL_SECTION
。我感谢Acorn和RaymondChen ...理智已恢复到宇宙的这个角落。
如果您的程序在WPO下崩溃(优化假设您正在编译的是整个程序),则意味着该假设不正确或优化器最终利用了一些以前未定义的行为(未应用优化) ),即使该假设是正确的。
通常,除非您确实确定自己满足要求,否则请避免启用优化。
为了进一步分析,请提供MRE。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句