简体   繁体   中英

Visual Studio C++ Runtime Issue with Multithreading on the Release Configuration

When I compile with the configuration set to release (for both x86 and x64), my program fails to complete. To clarify, there are no build errors or execution errors.

After looking for a cause and solution for the issue, I found Program only crashes as release build -- how to debug? which proposes that it is an array issue. Though this solve my problem, it gave me some insight on the matter (which I leave here for the next person).

To further muddle matters, it's only when a subroutine on the main thread has an execution time greater than about 0ms.

Here are the relevant sections of code:

//  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);

Where the offending line that my program gets stuck on is that last statement, where the program waits for the created thread to terminate:

WaitForSingleObject(progressBarHandle, INFINITE);

And here is the code for the progress bar function:

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;
}

Where the 'Core' while loop generally won't get a single iteration if the execution time of the measured subroutine is about 0ms. To clarify this, if the execution time of the timed subroutine is about 0ms, the nPC_Current will be greater than nPC_Max before the printProgressBar executes once. This means that thread will terminate before the main thread begins to wait for it.

If anyone would help with this, or provide some further insight on the matter, that would be fantastic as I'm having quite some trouble figuring this out.

Thanks!

edits:

  • wording
  • deleted distracting contents and added clarifications

My guess would be that you forgot to declare your shared global variables volatile ( nPC_Current specifically). Since the thread function itself never modifies nPC_Current , in the release version of the code the compiler optimized you progress bar loop into an infinite loop with never changing value of nPC_Current .

This is why your progress bar never updates from 0% value in release version of the code and this is why your progress bar thread never terminates.

PS Also, it appears that you originally intended to pass your nPC_Current counter to the thread function as a thread parameter (judging by your CreateThread call). However, in the thread function you ignore the parameter and access nPC_Current directly as a global variable. It might be a better idea to stick to the original idea of passing and accessing it as a thread parameter.

The number one rule in writing software is:

Leave nothing to chance; check for every single possible error, everywhere.

Note: this is the number one rule not when troubleshooting software; when there is trouble, it is already too late; this is the number one rule when writing software, that is, before there is even a need to troubleshoot.

There is a number of problems with your code; I cannot tell for sure that any one of those is what is causing you the problem that you are experiencing, but I would be willing to bet that if you fixed those, and if you developed the mentality of fixing problems like those, then you would not have the problem you are experiencing.

  1. The documentation for WaitForSingleObject says: "If this handle is closed while the wait is still pending, the function's behavior is undefined." However, you do not appear to be asserting that CreateThread() returned a valid handle. You are not even showing us where and how you are closing that handle. (And when you do close the handle, do you assert that CloseHandle() did not fail?)

  2. Not only you are using global variables, (which are something that I would strongly advice against,) but also, you happily make a multitude of assumptions about their values, without ever asserting any one of those assumptions.

    • What guarantees do you have that nPC_Current is in fact less than nPC_Max at the beginning of your function?

    • What guarantees do you have that nPC_Current keeps incrementing over time?

    • What guarantees do you have that the calculation of lastProgressPercent does not in fact keep yielding -1 during your loop?

    • What guarantees do you have that nPC_Max is not zero? (Division by zero on a separate thread is kind of hard to catch.)

    • What guarantees do you have that nPC_Max does not get also modified while your thread is running?

    • What guarantees do you have that nPC_Current gets incremented atomically? (I hope you understand that if it does not get incremented atomically, then at the moment that you read it from another thread, you may read garbage.)

You have tagged this question with [C++] , and I do see a few C++ features being used, but I do not really see any object-oriented programming. The thread function accepts an LPVOID parameter precisely so that you can pass an object to it and thus continue being object-oriented in your second thread, with all the benefits that this entails, like for example encapsulation. I would suggest that you use it.

You can use (with some limitations) breakpoints in release...

Does this part of the code:

/* Do stuff and time how long it takes (this is what increments nPC_Current) */

depend on what printProgress thread does? (If so, you have to assure time dependence, and order conveniently) Are you sure this is always incrementing nPC_Current ? Is it a time dependent algorithm? Have you tested the effect that a Sleep() has here?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM