当我使用配置设置为release(对于x86和x64)进行编译时,我的程序无法完成。为了澄清,没有构建错误或执行错误。
在查找问题的原因和解决方案后,我发现Program only crashes as release build -- how to debug?提出这是一个数组问题。虽然这解决了我的问题,但它给了我一些关于此事的见解(我将其留给下一个人)。
为了进一步混淆,只有当主线程上的子程序的执行时间大于约0ms时才会出现问题。
以下是相关的代码部分:
// Startup Progress Bar Thread
nPC_Current = 0; // global int
nPC_Max = nPC; // global int (max value nPC_Current will reach)
DWORD myThreadID;
HANDLE progressBarHandle = CreateThread(0, 0, printProgress, &nPC_Current, 0, &myThreadID);
/* Do stuff and time how long it takes (this is what increments nPC_Current) */
// Wait for Progress Bar Thread to Terminate
WaitForSingleObject(progressBarHandle, INFINITE);
我的程序被困在哪一行是最后一个语句,程序等待创建的线程终止:
WaitForSingleObject(progressBarHandle, INFINITE);
以下是进度条功能的代码:
DWORD WINAPI printProgress(LPVOID lpParameter)
{
int lastProgressPercent = -1; // Only reprint bar when there is a change to display.
// Core Progress Bar Loop
while (nPC_Current <= nPC_Max)
{
// Do stuff to print a text progress bar
}
return 0;
}
核心&#39;如果测量子程序的执行时间约为0ms,则while循环通常不会获得单次迭代。为了澄清这一点,如果定时子程序的执行时间约为0ms,则在printProgressBar执行一次之前,nPC_Current将大于nPC_Max。这意味着线程将在主线程开始等待之前终止。
如果有人愿意帮助解决这个问题,或者就此事提供一些进一步的见解,那就太棒了,因为我在解决这个问题时遇到了一些麻烦。
谢谢!
编辑:
答案 0 :(得分:6)
我的猜测是您忘记声明共享的全局变量volatile
(nPC_Current
具体而言)。由于线程函数本身从不修改nPC_Current
,因此在代码的发行版中,编译器优化了进度条循环到无限循环,永不改变nPC_Current
的值。
这就是为什么您的进度条永远不会从代码的发布版本中的0%
值更新,这就是您的进度条线程永远不会终止的原因。
P.S。此外,您最初打算将nPC_Current
计数器作为线程参数传递给线程函数(通过CreateThread
调用判断)。但是,在线程函数中,您忽略该参数并直接访问nPC_Current
作为全局变量。坚持传递和访问它作为线程参数的原始想法可能是一个更好的主意。
答案 1 :(得分:1)
编写软件的首要原则是:
不遗余力;检查每一个可能的错误,无处不在。
注意:这是排除软件故障时的头号规则 不 ;当遇到麻烦时,已经太晚了;这是编写软件时的头号规则,也就是说,甚至在需要进行故障排除之前。
您的代码存在许多问题;我无法确定其中任何一个是导致你遇到问题的原因,但我愿意打赌,如果你修复了这些问题,并且如果你养成了解决这些问题的心态,那么你会没有你遇到的问题。
WaitForSingleObject
的文档说:“如果在等待仍处于暂挂状态时关闭此句柄,则该函数的行为未定义。”但是,您似乎没有断言CreateThread()
返回了有效句柄。你甚至没有告诉我们你在哪里以及如何关闭这个句柄。 (当你关闭句柄时,你是否断言CloseHandle()
没有失败?)
不仅你正在使用全局变量(这是我强烈反对的建议),而且你很乐意对它们的值进行多种假设,而不会断言任何一种假设。 / p>
你有什么保证nPC_Current实际上比你函数开头的nPC_Max小?
你有什么保证nPC_Current会随着时间的推移而不断增加?
您有什么保证lastProgressPercent
的计算实际上在循环期间不会让-1
屈服?
您有什么保证nPC_Max 不为零? (在单独的线程上将零划分是很难捕捉的。)
你有什么保证nPC_Max在你的线程运行时不会也被修改?
你有什么保证nPC_Current以原子方式递增? (我希望你明白,如果它没有原子地增加,那么当你从另一个线程读取它时,你可能会读垃圾。)
您已使用[C++]
标记了此问题,我确实看到了一些正在使用的C ++功能,但我并没有真正看到任何面向对象的编程。线程函数精确地接受LPVOID
参数,以便您可以将对象传递给它,从而继续在第二个线程中面向对象,具有所需的所有好处,例如封装。我建议你使用它。
答案 2 :(得分:-1)
您可以在发布中使用(有一些限制)断点...
代码的这一部分是:
/* Do stuff and time how long it takes (this is what increments nPC_Current) */
取决于printProgress
线程的作用? (如果是这样,你必须确保时间依赖性,并且方便地订购)你确定这总是递增nPC_Current
吗?它是时间依赖算法吗?
您是否测试了Sleep()
在此处的效果?