Anyone know what do I need to step into to figure out what is failing -
there is nothing added to the Output window during close?
You must have a thread which has not been closed when you close
mainframe? Do you have any worker thread in your app?
---
Ajay
I do not create any new threads deliberately - how do I check for this?
You can check for number of threads in task manager. Perhaps you are
using a library which is doing something using a thread. I am not sure.
I dont see why else would you have this issue.
---
Ajay
After you attempt to close the app, and it is stuck, use the Break
command on the debug menu to find out what is executing. (Possibly a
thread you did not close?)
--
Scott McPhillips [VC++ MVP]
On Tue, 12 Dec 2006 09:47:40 -0500, "Scott McPhillips [MVP]" <org-dot-mvps-at-scottmcp>
wrote:
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Tom
"GT" <ContactG...@hotmail.com> wrote in message
news:457eaa6c$0$4317$c3e...@news.astraweb.com...
>It could be that a destructor on one of these objects is blocked waiting for its thread to
>finish; only if the GUI thread is blocked will the program remain visible in the task list
>(if the GUI thread terminates but other threads continue to run, it will not appear in the
>task list but *will* appear in the process list, which I sometimes refer to as "zombie
>processes" because they are not quite dead)
If by "GUI thread" you mean the process's main thread, then it is the
thread running the process's startup code, which is part of the CRT.
Control returns to the CRT when the main thread exits in the C++ sense,
which includes returning from main, calling exit, etc. Then the CRT starts
to destroy the process environment, which includes calling destructors on
global and local static objects. The last thing it does is call
ExitProcess, which kills any remaining secondary threads. There are only
two things that will keep a normal, native C or C++ program (including MFC
apps) alive when the main thread exits:
1. A deadlock or other flaw that prevents it from reaching its ExitProcess
call.
2. Something going on in a secondary thread that prevents ExitProcess from
killing the secondary thread. (I don't know what that might be, but I guess
it might include certain system calls.)
Ordinarily, the CRT makes it to ExitProcess, and the program terminates.
The important thing to take away from all this that it's a really bad idea
to allow secondary threads to continue to run while the main thread is
exiting and destroying the environment in which they run. Not only may they
not have completed their work, ripping the rug out from under them can
cause the program to malfunction as it exits.
P.S. Things are a bit different under .NET, which can behave as you
describe depending on the type of secondary thread you created.
--
Doug Harrison
Visual C++ MVP
>On Tue, 12 Dec 2006 17:01:37 -0500, Joseph M. Newcomer
><newc...@flounder.com> wrote:
>
>>It could be that a destructor on one of these objects is blocked waiting for its thread to
>>finish; only if the GUI thread is blocked will the program remain visible in the task list
>>(if the GUI thread terminates but other threads continue to run, it will not appear in the
>>task list but *will* appear in the process list, which I sometimes refer to as "zombie
>>processes" because they are not quite dead)
>
>If by "GUI thread" you mean the process's main thread, then it is the
>thread running the process's startup code, which is part of the CRT.
>Control returns to the CRT when the main thread exits in the C++ sense,
>which includes returning from main, calling exit, etc. Then the CRT starts
>to destroy the process environment, which includes calling destructors on
>global and local static objects. The last thing it does is call
>ExitProcess, which kills any remaining secondary threads. There are only
>two things that will keep a normal, native C or C++ program (including MFC
>apps) alive when the main thread exits:
>
>1. A deadlock or other flaw that prevents it from reaching its ExitProcess
>call.
>
>2. Something going on in a secondary thread that prevents ExitProcess from
>killing the secondary thread. (I don't know what that might be, but I guess
>it might include certain system calls.)
****
Yes, I'm referring to killing the main GUI thread. The problem is that ExitProcess won't
kill a thread that is blocked in the kernel, which is why the process hangs around. So a
thread blocked on a ReadFile or a WaitFor... will keep ExitProcess from completing.
Meanwhile, the actual windows have been destroyed, so there is no more visibility in the
task bar or the task manager. But if you click the "Processes" tab of the Task Manager,
you'll see the process. If you are running under the debugger, a break will reveal that
it is indeed blocked on a kernel call.
This is one of the reasons I advise students that you must never do synchronous I/O with
an unbounded wait time in any thread, primary or secondary. Instead, make sure that the
device can either time out in a finite and ideally settable period (such as a serial port
can), or use "pseudo-synchronous" I/O where you issue a ReadFile (typically ReadFile is
the culprit...) and then WFMO on the handle for shutdown and the handle for the I/O
request. Maybe even with a timeout. This guarantees that the thread will not stay
blocked indefinitely. And, of course, the usual caveats apply: that the correct shutdown
is to make sure the threads have finished before destroying the GUI, lest the thread try
to access an HWND or some other object which has already been destroyed.
****
>
>Ordinarily, the CRT makes it to ExitProcess, and the program terminates.
>The important thing to take away from all this that it's a really bad idea
>to allow secondary threads to continue to run while the main thread is
>exiting and destroying the environment in which they run. Not only may they
>not have completed their work, ripping the rug out from under them can
>cause the program to malfunction as it exits.
***
The number of client programs I've had to fix because they assumed the threads would "just
stop" is amazing. Either they hang indefinitely or they randomly take access faults as
they are closing. Actually, it's more like they've had the rug put down in front of them,
rather ripped out from under them. The point being that the rug is covering a large hole
that leads to the alligator pit...
****
>
>P.S. Things are a bit different under .NET, which can behave as you
>describe depending on the type of secondary thread you created.
>kill a thread that is blocked in the kernel, which is why the process hangs around. So a
>thread blocked on a ReadFile or a WaitFor... will keep ExitProcess from completing.
Here's a counter-example involving waiting on a mutex:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>
#include <stdio.h>
HANDLE hMutex;
unsigned __stdcall proc(void*)
{
puts("Secondary thread waiting forever on mutex...");
WaitForSingleObject(hMutex, INFINITE);
return 0;
}
int main()
{
hMutex = CreateMutex(0, true, 0);
unsigned id;
HANDLE hThread = (HANDLE) _beginthreadex(0, 0, proc, 0, 0, &id);
// Sleeping here is a non-robust way to address
// the race condition.
Sleep(5000);
puts("Main thread exiting...");
if (WaitForSingleObject(hThread, 0) != WAIT_TIMEOUT)
{
puts(" Cannot happen.");
return 1;
}
return 0;
}
The output I get is:
Secondary thread waiting forever on mutex...
Main thread exiting...
Checking Task Manager, a.exe is nowhere to be found in the process list.
GUI apps behave the same way. (Creating the mutex in another process that
outlives this one would eliminate any chance of the program influencing the
outcome by virtue of creating the mutex itself; this is harder to explain
and more verbose to post, and since it doesn't change anything in practice,
I went with the shorter, all-in-one example for clarity.)
>Meanwhile, the actual windows have been destroyed, so there is no more visibility in the
>task bar or the task manager. But if you click the "Processes" tab of the Task Manager,
>you'll see the process. If you are running under the debugger, a break will reveal that
>it is indeed blocked on a kernel call.
Replacing "proc" with the following ReadFile test doesn't change things:
unsigned __stdcall proc(void*)
{
puts("Secondary thread reading stdin...");
char c;
DWORD n;
ReadFile(GetStdHandle(STD_INPUT_HANDLE), &c, 1, &n, 0);
return 0;
}
Interestingly, replacing it with the following stdio test causes it to
stall as you described, but I think it must be happening before the CRT
gets to ExitProcess; running it under the debugger and tracing should clear
things up:
unsigned __stdcall proc(void*)
{
puts("Secondary thread reading stdin...");
getchar();
return 0;
"Doug Harrison [MVP]" <d...@mvps.org> wrote in message
news:r4sun2t19druacig9...@4ax.com...
>Easy. The mutex will be abandoned by the main thread, then the second thread
>will proceed and terminate.
Hence what I said:
>> (Creating the mutex in another process that
>> outlives this one would eliminate any chance of the program influencing
>> the
>> outcome by virtue of creating the mutex itself; this is harder to explain
>> and more verbose to post, and since it doesn't change anything in
>> practice,
>> I went with the shorter, all-in-one example for clarity.)
If it's not clear, I performed this test before posting. Try it with
CreateMutex in process X and OpenMutex in process Y, such that the former
process outlives the latter, and you'll get the result I reported. FWIW, I
think you're reading more into the ExitProcess documentation than is there;
I wouldn't think what you've stated happens deterministically.
Thank you all for your help. Problem was (as always) something simple, which
I had forgotten about: Problem was that in I had a AfxOleLockApp() call,
but I forgot to AfxOleUnlockApp()! All OK now. Simple mistake, but sometimes
the hardest ones to diagnose!
Man, those are some of the most difficult things to debug. I had one
recently where I'd done a critical section that never got undone and that
gave me similar results and ended up blocking my thread. It took me a few
minutes and I quickly rewrote that part of the code to make it less
mysterious.
Tom
"GT" <ContactG...@hotmail.com> wrote in message
news:457fd30c$0$332$c3e...@news.astraweb.com...
Wouldnt happen in a managed world :-)
---
Ajay
I don't think I was hallucinating. Generally the strongest drug I take is chocolate.
Some years ago a group of people I know were working on .NET-style security (long before
any of us had heard of .NET) by doing API trapping, and they were having problems killing
processes that were blocked in the kernel, so this may have been a serious problem at one
time. But it does not appear to be an issue now. I think it might have been in NT4.
joe
Tom
"Ajay Kalra" <ajay...@yahoo.com> wrote in message
news:1166036036....@n67g2000cwd.googlegroups.com...
There is always a initial cost as you paid with MFC etc. But the
benefits are substantial. Also, IMO you have to move away from C++ in
managed world. A complete break if you can. C# is an ideal language for
managed world.
---
Ajay
>I have indeed now tried three different experiments, all of which confirm that the
>programs exit. Yet years ago, and I'm wondering if this was an NT4 or MS-DOS thing,
>zombie processes were common problems. I was unable to get this to fail on XP, or on my
>visiting Win2K box. Yet in the past, if I attached a debugger to the zombie and looked at
>where it was stopped, it was always on a WF[SM]O or ReadFile operation in a secondary
>thread. When I redid the program (including a few of my own while I was learning
>threading) so the threads shut down gracefully, the problem went away.
Could have been a deadlock.
>I don't think I was hallucinating. Generally the strongest drug I take is chocolate.
When I hear "zombie", I think Unix. No comment on what Unix programming may
do to the mind. :)
>Some years ago a group of people I know were working on .NET-style security (long before
>any of us had heard of .NET) by doing API trapping, and they were having problems killing
>processes that were blocked in the kernel, so this may have been a serious problem at one
>time. But it does not appear to be an issue now. I think it might have been in NT4.
Clearly some processes resist attempts to terminate them via Task Manager.
It seems like I read something about this once, but I don't recall the
details.