When thread is just created and forgotten about - which is pretty common case for worker threads (ie with std.concurrency.spawn) it leaks the OS handle (at least on windows) as CloseHandle is not called in Thread destructor.
My guess is that it's because of these lines:
* https://github.com/dlang/druntime/blob/master/src/core/thread/osthread.d#L304
* https://github.com/dlang/druntime/blob/master/src/core/thread/osthread.d#L697
The last line yields true so CloseHandle isn't called in Thread destructor.
See the test case below and watch what happens with process handles ie in sysinternals procexp or handles utilities.
```D
import core.thread;
import core.time;
import std;
extern(C) __gshared string[] rt_options = [ "gcopt=parallel:0" ];
void main() {
writeln("press enter to start");
readln();
Thread[10] threads;
foreach (i; 0..10) threads[i] = new Thread(&threadFn).start();
Thread.sleep(1.seconds); // make sure they are done
foreach (i; 0..10) {
// threads[i].join(); # if joined, OS handle is closed as expected
destroy(threads[i]); # enforce destructors to be called
}
writeln("threads disposed, press enter to exit");
readln();
}
void threadFn() { }
```
Comment #1 by mail — 2020-05-25T11:01:56Z
This is the case as well under Linux.
With GDB attached I have put a breakpoint at the core.thread.osthread.Thread's destructor and confirmed it doesn't get run (I spawned 100k threads and let them run till finish).
As a workaround I am calling `pthread_detach(pthread_self);` right before the thread terminates. This is not a good solution though since the Thread's destructor (if it did ran), would also call pthread_detach, which results in undefined behaviour.
Better would be to do a thread_detachThis as well, since that will cause a different branch in the Thread's destructor and avoid the call to pthread_detach.
Sadly, using thread_detachThis and the pthread_detach I get spurious crashes in std.concurrency's tls module teardown (sometimes).
(In reply to Steven Schveighoffer from comment #2)
> When linking to github, use the `y` command to change the link to a
> hash-based link, otherwise your links get stale.
>
> For reference, here are the two links:
>
> https://github.com/dlang/druntime/blob/
> 19ef6336d1940e770d696dc71f7605eb3f618a85/src/core/thread/osthread.d#L304
> https://github.com/dlang/druntime/blob/
> 19ef6336d1940e770d696dc71f7605eb3f618a85/src/core/thread/osthread.d#L697
>
> Can you test again? the code has changed quite a bit since then, the
> destructor looks rewritten.
Yes I can still confirm it on both windows and linux.
Tried with dmd-2.098.0 on windows and build from current master on linux.
Added some logging to the Thread destructor with the output:
```D
press enter to start
~Thread()
~Thread()
~Thread()
~Thread()
~Thread()
~Thread()
~Thread()
~Thread()
~Thread()
~Thread()
threads disposed, press enter to exit
~Thread()
passed
detach
```
So currently, it won't pass this https://github.com/dlang/druntime/blob/abd43eb4e760667fc4b1ebe1fe07d29340265596/src/core/thread/osthread.d#L292
And sorry for not permanent links, younger me hasn't known all he knows now ;-)
Comment #4 by robert.schadek — 2024-12-07T13:40:06Z