Visual Studio 2017 社区中 C++ 调试与发布构建结果的差异
Difference in C++ Debug vs Release build results in Visual Studio 2017 Community
为什么调试模式构建给出的结果与发布模式构建不同?
#define devicecount 4
static const size_t c_maxCount = 4; // I should actually set it to devicecount
bool bstatus[devicecount];
bool cbflag[devicecount];
bool gbflag[devicecount];
#define dpacketlength 9
HANDLE hThreadMain[c_maxCount];
HANDLE hThreadGraph, hThreadComm;
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
// This snippet for reference only
// ...
int i;
mwnd p[c_maxCount];
for (i = 0; i < c_maxCount; i++) {
hThreadMain[i] = CreateThread(NULL, 0, MainThread, &p[i], 0, NULL);
}
mwnd g;
hThreadGraph = CreateThread(NULL, 0, UpdateGraph, &g, 0, NULL);
mwnd c;
hThreadComm = CreateThread(NULL, 0, CommThread, &c, 0, NULL);
// ...
}
// Following thread function has problem
DWORD WINAPI CommThread(LPVOID lParam) {
char data[(dpacketlength+10)] = { 0 }; // added "+ 10" later
unsigned int i;
char pbuf[2];
bool skip = 0;
while (1) {
skip = 0;
for (i = 0; i < c_maxCount; i++) {
//Sleep(20); // uncommenting it makes the code work
if (bstatus[i] == 1) { // device working
if (cbflag[i] == 0) { // data not ready
skip = 1; // skip, flag not set
}
}
}
//cout << ""; // uncommenting it makes the code work
if (skip == 1) {
continue;
}
cout << "."; // This is how I measure the program is progressing or not
// Some code to follow to send data over comm
// ...
// assign 9 bytes to data[] (always). 2*4 (always) for 4 devices and 1 extra parameter byte. if maxCount is < 4, the corresponding bytes are zero, as initialized INSHAALLAH.
for (i = 0; i < c_maxCount; i++) {
// compute pbuf[]s
data[(2 * i)] = pbuf[0];
data[((2 * i) + 1)] = pbuf[1];
}
data[8] = (char)par;
// some code that loops over data[] from data[0] to data[8] and sends bytes over comm
// ...
for (i = 0; i < c_maxCount; i++) {
cbflag[i] = 0;
}
}
}
我是用Win32写的这个软件,附带一个调试用的控制台。代码片段来自 "comm" 线程。还有其他 c_maxCount
"Main" 个线程,每个线程都分配了 cbflag[]
中的一个元素。
这些线程检查设备是否在线,如果在线,则它们获取数据并准备各自的全局缓冲区。完成后,他们设置相应的 cbflag[i]
。在相应的 cbflag[i]
重置为 0 之前,它们不会接触缓冲区。
还有另一个线程 "Graph" 实时在屏幕上绘图。 Graph线程在设置gbflag[]
中的任意一项(对应每个Main线程)时绘制,绘制完成后重置gbflag[i]
。绘图在发布版本中冻结,我开始通过将 cout
s 放入代码中进行调试。显然主线程无限期地等待,因为 cbflag[]
s 没有在函数结束时这段代码的第三个 for
循环中被重置,因为代码被 skip
ped/ continue
d。这是我发现如果我在检查 skip
之前放置 cout
,即使它打印空字符串,代码也会以某种方式工作。 "work",我的意思是代码的下半部分没有 skip
ped。所以现在我无法在不影响系统的情况下进行调试。
此外,我尝试将消息框放在第一个 for 循环中并在检查跳过之前,但它仍然影响代码并开始工作。
如果我将 c_maxCount
更改为 1,它会开始工作并且不会跳过。
如果我取消注释 Sleep(20)
行,它会起作用并且不会跳过。
但是,如果我插入一个代码来为变量赋值来代替 cout
或 Sleep()
,它不起作用,因此它不会影响行为。
我在 Whosebug 上读到,在发布应用程序崩溃的情况下,它主要与数组边界有关。我增加了 data[]
数组但无济于事。
我已经通过定期打印到标签中的屏幕来检查图形线程中 bstatus[]
和 cbflag[]
的值,它们对于两个数组的所有元素都是 1。
由于cbflag
被一个线程修改并在另一个线程中读取,所以应该是std::atomic
。编译器可能会对影响发布版本的非原子全局变量(即它们未被修改)做出假设,而它不会在调试版本中进行。
为什么调试模式构建给出的结果与发布模式构建不同?
#define devicecount 4
static const size_t c_maxCount = 4; // I should actually set it to devicecount
bool bstatus[devicecount];
bool cbflag[devicecount];
bool gbflag[devicecount];
#define dpacketlength 9
HANDLE hThreadMain[c_maxCount];
HANDLE hThreadGraph, hThreadComm;
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
// This snippet for reference only
// ...
int i;
mwnd p[c_maxCount];
for (i = 0; i < c_maxCount; i++) {
hThreadMain[i] = CreateThread(NULL, 0, MainThread, &p[i], 0, NULL);
}
mwnd g;
hThreadGraph = CreateThread(NULL, 0, UpdateGraph, &g, 0, NULL);
mwnd c;
hThreadComm = CreateThread(NULL, 0, CommThread, &c, 0, NULL);
// ...
}
// Following thread function has problem
DWORD WINAPI CommThread(LPVOID lParam) {
char data[(dpacketlength+10)] = { 0 }; // added "+ 10" later
unsigned int i;
char pbuf[2];
bool skip = 0;
while (1) {
skip = 0;
for (i = 0; i < c_maxCount; i++) {
//Sleep(20); // uncommenting it makes the code work
if (bstatus[i] == 1) { // device working
if (cbflag[i] == 0) { // data not ready
skip = 1; // skip, flag not set
}
}
}
//cout << ""; // uncommenting it makes the code work
if (skip == 1) {
continue;
}
cout << "."; // This is how I measure the program is progressing or not
// Some code to follow to send data over comm
// ...
// assign 9 bytes to data[] (always). 2*4 (always) for 4 devices and 1 extra parameter byte. if maxCount is < 4, the corresponding bytes are zero, as initialized INSHAALLAH.
for (i = 0; i < c_maxCount; i++) {
// compute pbuf[]s
data[(2 * i)] = pbuf[0];
data[((2 * i) + 1)] = pbuf[1];
}
data[8] = (char)par;
// some code that loops over data[] from data[0] to data[8] and sends bytes over comm
// ...
for (i = 0; i < c_maxCount; i++) {
cbflag[i] = 0;
}
}
}
我是用Win32写的这个软件,附带一个调试用的控制台。代码片段来自 "comm" 线程。还有其他 c_maxCount
"Main" 个线程,每个线程都分配了 cbflag[]
中的一个元素。
这些线程检查设备是否在线,如果在线,则它们获取数据并准备各自的全局缓冲区。完成后,他们设置相应的 cbflag[i]
。在相应的 cbflag[i]
重置为 0 之前,它们不会接触缓冲区。
还有另一个线程 "Graph" 实时在屏幕上绘图。 Graph线程在设置gbflag[]
中的任意一项(对应每个Main线程)时绘制,绘制完成后重置gbflag[i]
。绘图在发布版本中冻结,我开始通过将 cout
s 放入代码中进行调试。显然主线程无限期地等待,因为 cbflag[]
s 没有在函数结束时这段代码的第三个 for
循环中被重置,因为代码被 skip
ped/ continue
d。这是我发现如果我在检查 skip
之前放置 cout
,即使它打印空字符串,代码也会以某种方式工作。 "work",我的意思是代码的下半部分没有 skip
ped。所以现在我无法在不影响系统的情况下进行调试。
此外,我尝试将消息框放在第一个 for 循环中并在检查跳过之前,但它仍然影响代码并开始工作。
如果我将 c_maxCount
更改为 1,它会开始工作并且不会跳过。
如果我取消注释 Sleep(20)
行,它会起作用并且不会跳过。
但是,如果我插入一个代码来为变量赋值来代替 cout
或 Sleep()
,它不起作用,因此它不会影响行为。
我在 Whosebug 上读到,在发布应用程序崩溃的情况下,它主要与数组边界有关。我增加了 data[]
数组但无济于事。
我已经通过定期打印到标签中的屏幕来检查图形线程中 bstatus[]
和 cbflag[]
的值,它们对于两个数组的所有元素都是 1。
由于cbflag
被一个线程修改并在另一个线程中读取,所以应该是std::atomic
。编译器可能会对影响发布版本的非原子全局变量(即它们未被修改)做出假设,而它不会在调试版本中进行。