Discussion:
detached threads in Win32
(too old to reply)
Alicia
2004-02-10 04:31:15 UTC
Permalink
Greetings:

I am porting Unix pthread code to Win32, and have not found any thing
equivalent to "pthread_detach".

If I create threads using CreateThread, and never call WaitForSingleObject
or WaitForMultipleObjects for these threads, do I get a memory leak?

Consider the following program, that continuously creates threads, and
then forgets about them. Those created threads exit immediately on
their own. However, if I never join those created threads with a call to
WaitForSingleObject or WaitForMultipleObjects, will any type of memory
leak occur? Will the program continuous store all of the return states of
each thread as it finishes, and never release the data?

// #################################################################
DWORD start (void *data)
{
printf ("Started thread #%d!\n", (int) data);
return 0;
}
int main (int argc, char **argv)
{
HANDLE thread;
int j;
for (j = 0; j < 100000000; j++)
{
thread = CreateThread (NULL, 0, start, (void *) j, 0, NULL);
Sleep (200);
}
return 0;
}
// #################################################################

Thanks in advance.
Alicia.

PS. Please e-mail me back by replacing the "nospam" portion of my e-mail
address with my name "alicia".
Michael Sparks
2004-02-10 05:15:19 UTC
Permalink
Post by Alicia
Consider the following program, that continuously creates threads, and
then forgets about them. Those created threads exit immediately on
their own. However, if I never join those created threads with a call to
WaitForSingleObject or WaitForMultipleObjects, will any type of memory
leak occur? Will the program continuous store all of the return states of
each thread as it finishes, and never release the data?
[...]
thread = CreateThread (NULL, 0, start, (void *) j, 0, NULL);
[...]
Add a call to CloseHandle(thread) so that you release your handle to the
thread, and everything should be cleaned up fine.
Note that this program design is still pretty unsafe since your main thread
won't know when it is safe to exit the program without clobbering any of the
threads that may still be running.

Mike
xbunny
2004-02-10 10:17:58 UTC
Permalink
Post by Michael Sparks
Post by Alicia
Consider the following program, that continuously creates threads, and
then forgets about them. Those created threads exit immediately on
their own. However, if I never join those created threads with a call to
WaitForSingleObject or WaitForMultipleObjects, will any type of memory
leak occur? Will the program continuous store all of the return states of
each thread as it finishes, and never release the data?
[...]
thread = CreateThread (NULL, 0, start, (void *) j, 0, NULL);
[...]
Add a call to CloseHandle(thread) so that you release your handle to the
thread, and everything should be cleaned up fine.
Note that this program design is still pretty unsafe since your main thread
won't know when it is safe to exit the program without clobbering any of the
threads that may still be running.
Mike
Just wanted to add that your thread uses printf which is a C runtime
function. However you create your threads with CreateThread. In many
environments (anything which uses the Microsoft C Runtime - not so sure
about cygwin or others) this will create problems as the C runtine needs
to initialize per thread data for each thread that uses it and clean
that up at thread exit. The problem would be fixed by using
_beginthreadex rather than CreateThread or not using printf.

A related note maybe is that perhaps you can use one of the win32 ports
of pthreads?
Ziv Caspi
2004-02-11 22:28:33 UTC
Permalink
Post by xbunny
Just wanted to add that your thread uses printf which is a C runtime
function. However you create your threads with CreateThread. In many
environments (anything which uses the Microsoft C Runtime - not so sure
about cygwin or others) this will create problems as the C runtine needs
to initialize per thread data for each thread that uses it and clean
that up at thread exit. The problem would be fixed by using
_beginthreadex rather than CreateThread or not using printf.
Only if you use the static link CRTL. If you link dynamically (which you
really should) there's no such problem.

Ziv
xbunny
2004-02-12 13:14:31 UTC
Permalink
Post by Ziv Caspi
Post by xbunny
Just wanted to add that your thread uses printf which is a C runtime
function. However you create your threads with CreateThread. In many
environments (anything which uses the Microsoft C Runtime - not so sure
about cygwin or others) this will create problems as the C runtine needs
to initialize per thread data for each thread that uses it and clean
that up at thread exit. The problem would be fixed by using
_beginthreadex rather than CreateThread or not using printf.
Only if you use the static link CRTL. If you link dynamically (which you
really should) there's no such problem.
Ziv
no the dll version requires beginthreadex too
Alexander Terekhov
2004-02-12 13:22:12 UTC
Permalink
xbunny wrote:
[...]
Post by xbunny
Ziv
no the dll version requires beginthreadex too
Ziv, show xbunny the code. ;-) TLS dtors is the way to go, of course.

regards,
alexander.
Ziv Caspi
2004-02-13 09:53:47 UTC
Permalink
Post by Alexander Terekhov
Post by xbunny
no the dll version requires beginthreadex too
Ziv, show xbunny the code. ;-) TLS dtors is the way to go, of course.
It starts something like this:

C:\>debug %windir%\system32\msvcrt.dll
-u

Now repeat..

Ziv
Tim Robinson
2004-02-14 00:07:23 UTC
Permalink
Post by Ziv Caspi
C:\>debug %windir%\system32\msvcrt.dll
-u
Now repeat..
Nice try :).

Really you want IDA. DEBUG.COM only does 16 bits.
--
Tim Robinson (MVP, Windows SDK)
http://www.themobius.co.uk/
Ziv Caspi
2004-02-14 22:08:03 UTC
Permalink
Post by Tim Robinson
Post by Ziv Caspi
C:\>debug %windir%\system32\msvcrt.dll
-u
Now repeat..
Nice try :).
Really you want IDA. DEBUG.COM only does 16 bits.
In my defense, last time I used DEBUG.COM was when 16 bits was all we
had...

Ziv

Alicia
2004-02-10 13:42:29 UTC
Permalink
Post by Michael Sparks
Post by Alicia
Consider the following program, that continuously creates threads, and
then forgets about them. Those created threads exit immediately on
their own. However, if I never join those created threads with a call to
WaitForSingleObject or WaitForMultipleObjects, will any type of memory
leak occur? Will the program continuous store all of the return states of
each thread as it finishes, and never release the data?
[...]
thread = CreateThread (NULL, 0, start, (void *) j, 0, NULL);
[...]
Add a call to CloseHandle(thread) so that you release your handle to the
thread, and everything should be cleaned up fine.
Thank you Mike:

It looks like CloseHandle(thread) is exactly what I need. However, if
the thread is running, will running CloseHandle in the main thread
clobber it?

The simplied example above was just to illustrate what I needed. In
practice the main thread would run forever (until it receives a kill
signal or Win32 equalivant), and the main thread would be listening
in for TCP connections (for a service like FTP), then create a client
handling thread to deal with the specific client connected to it.
Since clients can be connected by FTP for a few seconds or many hours,
and since multiple clients can be connected at once, the main thread
can just forget about them and never join those client handling
threads.
Post by Michael Sparks
Note that this program design is still pretty unsafe since your main thread
won't know when it is safe to exit the program without clobbering any of the
threads that may still be running.
I did not know this was the case for Win32. In "pthreads", threads
in a program can continue to run after the main program returns from
main, as long as it doesn't call exit().

Thanks again for you very helpful advice.
Alicia.
Michael Sparks
2004-02-10 15:35:34 UTC
Permalink
Post by Alicia
It looks like CloseHandle(thread) is exactly what I need. However, if
the thread is running, will running CloseHandle in the main thread
clobber it?
No, the thread will continue to run - you will just lose your ability to
refer to it. Technically, you could hang on to the DWORD thread identifier
and subsequently use it to open a new thread handle (to the same thread) if
you needed to communicated. The DWORD thread identifier is analogous to a
filename, for example.
Post by Alicia
I did not know this was the case for Win32. In "pthreads", threads
in a program can continue to run after the main program returns from
main, as long as it doesn't call exit().
Someone please jump in and correct me if I'm wrong on this, but I'm pretty
sure that it isn't the case in win32.
You could still have safety without hanging on to the thread handles. You
could have a global variable that gets initialized to zero at startup, and
prior to creating each thread, use the InterlockedIncrement function to
increment the variable in a thread-safe way. As each thread exits (be sure
to use try/finally for this), the thread can call InterlockedDecrement on
that global variable. This way, your main thread can wait until the thread
count is zero before exiting.

HTH
Mike
Patrick TJ McPhee
2004-02-10 17:28:20 UTC
Permalink
In article <aT6Wb.14365$***@newssvr22.news.prodigy.com>,
Michael Sparks <***@remove.this.sbcglobal.net> wrote:
% "Alicia" <***@engine.ca> wrote in message

% > I did not know this was the case for Win32. In "pthreads", threads
% > in a program can continue to run after the main program returns from
% > main, as long as it doesn't call exit().
%
% Someone please jump in and correct me if I'm wrong on this, but I'm pretty
% sure that it isn't the case in win32.

You can always try it out, but I'm equally sure you can call
ExitThread() from the thread running main() or WinMain(). Note that
nobody ever does this, because there's typically IPC going on involving
the main() thread's message queue (because, against all reason, message
queues in win32 are thread attributes). This is especially important in
windowed applications, but it's also true in a large class of server
applications.
--
Patrick TJ McPhee
East York Canada
***@interlog.com
Stephen Kellett
2004-02-10 16:13:20 UTC
Permalink
Post by Michael Sparks
Someone please jump in and correct me if I'm wrong on this, but I'm pretty
sure that it isn't the case in win32.
Not so much a correction as more evidence to reinforce your claim:

From what I've seen writing low level tools, once any thread enters
ExitProcess() and starts the application shutdown you can't
realistically stop the application from terminating. I've done some
clever stuff with assembly overwrites to redirect dllMain to get extra
processing done - short of doing that and WaitForSingleObject() or
something else you can't really stop the app at that point.

If you look at the code that calls main() in the CRT, it calls
ExitProcess pretty soon afterwards (*), so game over on that score.

(*) It does have to call all the atexit/onexit functions and global
destructors though, so you can put in a delay/wait at that point. I
wouldn't think that was very good program design, but whatever you need
to do...

Stephen
--
Stephen Kellett
Object Media Limited http://www.objmedia.demon.co.uk
RSI Information: http://www.objmedia.demon.co.uk/rsi.html
David Butenhof
2004-02-11 12:55:42 UTC
Permalink
Post by Alicia
Post by Michael Sparks
Note that this program design is still pretty unsafe since your main
thread won't know when it is safe to exit the program without clobbering
any of the threads that may still be running.
I did not know this was the case for Win32. In "pthreads", threads
in a program can continue to run after the main program returns from
main, as long as it doesn't call exit().
That's not quite true, though in practice it may appear that way. When the
initial thread returns from main() in a POSIX program, the effect is
identical to that of a call to exit() -- the PROCESS terminates.

However, that termination does not involve controlled termination of any
other threads running in the process. They all "evaporate" when the _exit()
kernel call is eventually made by exit(), but they continue running until
that point, meaning through most of the exit() routine, file stream flush
and close, and any other state rundown. This is important because otherwise
you can run into all sorts of problems... but you can also run into
problems if exit handlers (either builtin C runtime cleanup or some other
library's atexit() cleanup) removes data required by another thread.

But this is all "boundary conditions" -- returning from main() WILL
terminate the process exactly as calling exit() with the same return value
as an argument. The only way the process can continue running
"indefinitely" after the main thread terminates is if you deliberately
terminate the main thread (not the process) by calling pthread_exit().
--
/--------------------[ ***@hp.com ]--------------------\
| Hewlett-Packard Company Tru64 UNIX & VMS Thread Architect |
| My book: http://www.awl.com/cseng/titles/0-201-63392-2/ |
\----[ http://homepage.mac.com/dbutenhof/Threads/Threads.html ]---/
Norman Black
2004-02-10 20:24:23 UTC
Permalink
Post by Alicia
I am porting Unix pthread code to Win32, and have not found any thing
equivalent to "pthread_detach".
The Win32 threading system is different and there is no need for
pthread_detach. Use CloseHandle to "close" a thread such that it will be
fully cleaned up when the thread terminates. CloseHandle only closes the
thread handle. It does not terminate a thread. A thread becomes a zombie
if it terminates and there are outstanding thread handles still open. In
this case the thread is not 100% cleaned up until the last outstanding
thread handle is closed. A significant amount of code never needs the
thread handle and in these situations you simply close the thread handle
just after you create the thread.

--
Norman Black
Stony Brook Software
Post by Alicia
I am porting Unix pthread code to Win32, and have not found any thing
equivalent to "pthread_detach".
If I create threads using CreateThread, and never call
WaitForSingleObject
Post by Alicia
or WaitForMultipleObjects for these threads, do I get a memory leak?
Consider the following program, that continuously creates threads, and
then forgets about them. Those created threads exit immediately on
their own. However, if I never join those created threads with a call to
WaitForSingleObject or WaitForMultipleObjects, will any type of memory
leak occur? Will the program continuous store all of the return states of
each thread as it finishes, and never release the data?
// #################################################################
DWORD start (void *data)
{
printf ("Started thread #%d!\n", (int) data);
return 0;
}
int main (int argc, char **argv)
{
HANDLE thread;
int j;
for (j = 0; j < 100000000; j++)
{
thread = CreateThread (NULL, 0, start, (void *) j, 0, NULL);
Sleep (200);
}
return 0;
}
// #################################################################
Thanks in advance.
Alicia.
PS. Please e-mail me back by replacing the "nospam" portion of my e-mail
address with my name "alicia".
Loading...