C++ InitializeCriticalSection在一个项目中工作,但在另一个项目中失败

C++ InitializeCriticalSection在一个项目中工作,但在另一个项目中失败,c++,critical-section,C++,Critical Section,在Windows 10 x64上使用Visual Studio 2019 Professional。我有几个C++ DLL项目,其中一些是多线程的。我正在使用CRITICAL\u部分对象来实现线程安全 在DLL1中: CRITICAL_SECTION critDLL1; InitializeCriticalSection(&critDLL1); 在DLL2中: CRITICAL_SECTION critDLL2; InitializeCriticalSection(&critD

在Windows 10 x64上使用Visual Studio 2019 Professional。我有几个C++ DLL项目,其中一些是多线程的。我正在使用
CRITICAL\u部分
对象来实现线程安全

在DLL1中:

CRITICAL_SECTION critDLL1;
InitializeCriticalSection(&critDLL1);
在DLL2中:

CRITICAL_SECTION critDLL2;
InitializeCriticalSection(&critDLL2);
当我将critDLL1与
EnterCriticalSection
LeaveCriticalSection
一起使用时,在
\u DEBUG
NDEBUG
模式下,一切正常。但是当我使用critDLL2时,我在
NDEBUG
中的“ntdll.dll”中得到了一个访问冲突(尽管不是在
\u DEBUG
中)

NDEBUG
模式下弹出消息框后,我最终能够跟踪问题,直到第一次使用
EnterCriticalSection

是什么原因导致
关键部分在一个项目中失败,但在其他项目中起作用?这是没有帮助的

更新1

在比较了DLL1(工作)和DLL2(不工作)的项目设置之后,我意外地发现DLL2正在工作。我通过恢复到早期版本(崩溃),然后对项目进行更改(没有崩溃!)来确认这一点

这是设置:

Project Properties > C/C++ > Optimization > Whole Program Optimization
将此设置为
Yes(/GL)
,我的程序就会崩溃。将其更改为
,即可正常工作。
/GL
开关的作用是什么?它为什么会导致此崩溃

更新2

@Acorn的出色回答和@RaymondChen的评论为追踪并解决问题提供了线索。有两个问题(都是程序员错误)

问题1

整个程序优化(wPO)的假设是MSVC编译器正在编译“整个程序”。对于我的DLL项目来说,这是一个错误的假设,它在内部使用第三方库,反过来又被用Delphi编写的外部应用程序使用。此设置默认设置为
Yes(/GL)
,但应为
No
。这感觉像是VisualStudio中的一个bug,但无论如何,程序员都需要意识到这一点。我不知道
WPO
要做什么的所有细节,但至少对于其他应用程序使用的DLL,应该更改默认设置

问题2

严重的程序员错误。这是对第三方库的调用,该库返回一个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\u pLib->GetPara(XPARA\u PRODUCT\u INFO,…)
是对第三方库的第一次调用,其余连续数据在该点上大部分为空


问题绝不是与
关键部分有关。我对橡子和雷蒙辰的感谢。。。理智已经恢复到宇宙的这个角落。

如果您的程序在WPO(一种假设您正在编译的任何东西都是整个程序的优化)下崩溃,这意味着要么该假设不正确,要么优化器最终利用了一些以前未定义的行为(未应用优化),即使假设正确

通常,避免启用优化,除非您确实确定自己满足了它们的要求


为了进一步分析,请提供一个。

我20多年来从未见过它失败过……您有一些代码可以看吗?可能是离题的,但由于您使用的是Visual Studio 2019,我将使用标准的C++11/14等线程函数,而不是低级的Windows函数。是的,我们需要知道调用这些函数的位置和时间ed.只有两条孤立的行并没有真正的帮助。@MichaëlRoy:是的,这就是问题所在。这是一个大项目。该死,我一直在摆弄这两个项目的属性页(逐个比较设置)…现在
critdl2
可以在不崩溃的情况下使用。将尝试返回跟踪、复制和报告。要测试此理论,您可以尝试在DLL2中的
InitializeCriticalSection
调用上设置断点。然后查看断点是否命中。如果调试器说它无法在那里设置断点,因为“没有可执行代码与此行相关联”,然后编译器得出结论,认为该代码在法律上是不可访问的,并将其删除。@Acorn.谢谢。当创建DLL项目时,
WPO
在默认情况下处于打开状态,这不是我的项目的正确假设。DLL由外部应用程序(用Delphi编写)使用,所以
WPO
绝对是一个过于优化的问题。奇怪的是,既然它是一个DLL项目,为什么MSVC编译器不能解决这个问题呢?这里发生了一些有趣的事情,我将尝试生成一个MRE…@RaymondChen:谢谢你的评论。通过对我的
Debug
构建进行两次更改,我能够将它转到crash:(1)
C/C++>General>调试信息格式=/Zi
,(2)
C/C++>Optimization>整个程序优化=Yes(/GL)
。现在调试构建崩溃了,我可以单步执行并找出发生了什么。当
关键\u部分
第一次初始化时,
DebugInfo=0xffffff
。我可以
EnterCriticalSection(&crit);
。在某个时候,
DebugInfo
更改为
0x00000000
,然后
EnterCriticalSection(&crit)
崩溃。更改发生在对第三方库的调用上,嗯?Acorn/Raymond:非常感谢…找到了问题!程序员错误-是对第三方库的调用。他们的文档说调用返回了“128字节ASCII码”,但直到终止NULL为止总是远远小于此值,所以我分配的字节数少于128字节(确切地说是字符序列[21])当我打电话到图书馆时,我开始复写