Visual Studio 2017 社区中 C++ 调试与发布构建结果的差异 [关闭]

Posted

技术标签:

【中文标题】Visual Studio 2017 社区中 C++ 调试与发布构建结果的差异 [关闭]【英文标题】:Difference in C++ Debug vs Release build results in Visual Studio 2017 Community [closed] 【发布时间】:2020-03-19 21:09:07 【问题描述】:

为什么调试模式生成的结果与发布模式生成不同?

#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 编写了这个软件,并附带了一个用于调试的控制台。代码 sn-p 来自“comm”线程。还有其他c_maxCount“主”线程,每个线程都分配了一个cbflag[]元素。 这些线程检查设备是否在线,如果在线,则它们获取数据并准备各自的全局缓冲区。完成后,他们设置各自的cbflag[i]。在各自的 cbflag[i] 重置为 0 之前,它们不会接触缓冲区。

还有另一个线程“Graph”在屏幕上实时绘制。 Graph线程在设置gbflag[]中的任何一个时进行绘制(对应于每个Main线程),并在绘制后重置gbflag[i]。绘图在发布版本中冻结,我开始通过将couts 放入代码中进行调试。显然,主线程无限期地等待,因为cbflag[]s 没有在函数结束时此代码的第三个for 循环中被重置,因为代码是skipped/continued。这是当我发现如果我在检查skip 之前输入cout,即使它打印空字符串,代码也会以某种方式工作。 “工作”是指代码的下半部分不是skipped。所以现在我无法在不影响系统的情况下进行调试。 此外,我尝试将消息框放在第一个 for 循环中并在检查跳过之前,但它仍然会影响代码并且它开始工作。 如果我将c_maxCount 更改为 1,它会开始工作并且不会跳过。 如果我取消注释 Sleep(20) 行,它会起作用并且不会跳过。 但是,如果我插入代码以将值分配给变量而不是 coutSleep(),则它不起作用,因此不会影响行为。

我在 *** 上读到,在发布应用程序崩溃的情况下,它主要与数组边界有关。我增加了data[] 数组,但无济于事。

我通过定期在标签中打印到屏幕,检查了 Graph 线程中 bstatus[]cbflag[] 的值,对于两个数组的所有元素,它们都是 1。

【问题讨论】:

MainThreadCommThread 应该是一样的吗? 不,它们是不同的。 4 MainThread 1 CommThread 1 GraphThread Sinice cbflag被一个线程修改并读入另一个线程,应该是std::atomic。编译器可能会对非原子全局变量(即它们没有被修改)做出假设,这些变量会影响它不会在调试版本中进行的发布版本。 为了清晰起见,我刚刚更新了代码。我会同时考虑你的建议 INSHAALLAH。 @speedbooster -- 多线程程序不仅仅是启动一些线程并使用普通的旧bool 变量来控制事物。它比你想象的要复杂得多。 【参考方案1】:

由于cbflag被一个线程修改并读入另一个线程,它应该是std::atomic。编译器可能会对非原子全局变量(即它们没有被修改)做出假设,这些变量会影响它不会在调试版本中进行的发布版本。

【讨论】:

以上是关于Visual Studio 2017 社区中 C++ 调试与发布构建结果的差异 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Visual Studio 社区 2017 cl.exe

Visual Studio 2017 社区中 C++ 调试与发布构建结果的差异 [关闭]

如何在 Visual Studio 2017 社区版的 IIS Express 中使用 php

Visual Studio C++ 社区 2017 中的构建错误

从 Visual Studio 2017 社区升级到 Pro

C++ Visual Studio 函数语法高亮