I've been using threads for 20 years on Unix and just learning them on Windows, with Visual Studio 2008.
My app is dialogs-based MFC GUI, with four main "peer" windows (none of them a "main" window). When MyApp::InitInstance() starts, the Debug->Windows->Threads window reports just a single thread, MainThread. As I step past the first CDialog::Create()
call, 3 worker threads are created. I don't know what these are and would love to--and especially would love a reference to a full explanation book or web page. I tried putting a breakpoint on CreateThread()
but VS2008 reports: The function cannot be found.
in the hover over the !
icon in the Breakpoints window. I also cannot single-step into it if I break in a function that calls it. I assume its a system call and as kernel code VS08 can't reach into it.
I then create a worker thread that outputs audio and is set to THREAD_PRIORITY_TIME_CRITICAL. This has worked stably for a long time.
However once my app leaves MyApp::InitInstance(), there is a mystery thread created with "Priority" shown as -8 in the Debug Threads window. I don't know what that thread is. Any ideas or pointers to resources? I tried putting a breakpoint on SetThreadPriority()
, assuming that I'd hit that in whatever code is setting it to this non-vanilla priority, and just as CreateThread()
, it isn't a known function.
And on to the actual issue, as opposed to mere mystery: in shutting down my app, I'm destructing and freeing all the memory I used, and getting a crash in this "-8" thread while I do so. There's no source, just assembly, and no stack trace or symbols. There's no hint from the program that its heap corruption, such as symbols appearing on on its stack or the Output window.
The only extra info I can think to give about the app is that:
-- it receives MIDI events fine and has for years
-- it has one worker thread, calculating data for a sound buffer; I set a sentinel boolean flag and wait for it to end with GetExitCodeThread()
; I indeed get the exit code so I'm sure this isn't the -8 thread. (And its priority is "TimeCritical" anyway, not -8)
-- everything is problem free except for memory leaks, which I'm addressing now using _CRTDBG_MAP_ALLOC
. Without freeing data, I'm not having the crash. But having found out what exact object is causing the problem, I'm still at a loss because--again--I haven't actually created a thread that refers to that object.
Thanks to your help in figuring out how to breakpoint the thread creation. It became instantly clear that it was being created inside the audio processing library. As one gives that library a block of memory containing samples to play, and I had free'd that was the prime candidate.
Reading between the lines of the Microsoft documentation, I found two additional functions that might potentially shut down such a thread (to wit waveOutReset()
and waveOutClose()
. After calling those, the access violations have disappeared. With this type of bug its hard to be positive, but for me this seems like a likely cause of the problem.
For years, the program simply exited upon user command, without deallocating storage, and didn't have issues. It was only upon adding cleanup code that the problem became visible. These facts also support the suspected cause.