Skip to content

Conversation

@CyberShadow
Copy link
Member

Add a new join(Tid) function that allows explicit joining of threads created by spawn(). This prevents OS resource leaks in long-running applications that create many short-lived threads.

Without calling join(), thread stacks (~8 MB each on typical systems) accumulate in virtual memory for the lifetime of the process because:

  • Threads created by spawn() are never explicitly joined
  • Thread objects remain in the global thread list until process exit
  • pthread cannot free thread stacks until pthread_join() is called

The new join() function:

  • Blocks until the thread completes
  • Releases OS resources (stack, TLS) via pthread_join()
  • Throws ThreadError if used on scheduler-created threads
  • Throws ThreadError if the thread was already joined

Motivating example:

import std;
import core.thread;

void worker() { Thread.sleep(1.msecs); }

void printVmSize() {
    "/proc/self/status".readText.splitLines
        .filter!(l => l.startsWith("VmSize:"))
        .front.writeln;
}

void main()
{
    printVmSize();

    foreach (i; 0 .. 1000)
    {
        auto tid = spawn(&worker);
        version (doNotLeakMemory) tid.join();
    }

    Thread.sleep(100.msecs); // ensure all tasks finished

    printVmSize();
}

Output:

$ dmd std/**/*.d example_join.d -of=./t_join && ./t_join              
VmSize:	    9972 kB
VmSize:	33310900 kB

$ dmd std/**/*.d example_join.d -of=./t_join -version=doNotLeakMemory && ./t_join               
VmSize:	    9972 kB
VmSize:	   87948 kB

Add a new `join(Tid)` function that allows explicit joining of threads
created by spawn(). This prevents OS resource leaks in long-running
applications that create many short-lived threads.

Without calling join(), thread stacks (~8 MB each on typical systems)
accumulate in virtual memory for the lifetime of the process because:
- Threads created by spawn() are never explicitly joined
- Thread objects remain in the global thread list until process exit
- pthread cannot free thread stacks until pthread_join() is called

The new join() function:
- Blocks until the thread completes
- Releases OS resources (stack, TLS) via pthread_join()
- Throws ThreadError if used on scheduler-created threads
- Throws ThreadError if the thread was already joined

Testing shows:
- Without join: ~8,200 KB virtual memory per thread (stacks leak)
- With join: ~38 KB per thread (stacks properly freed)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@dlang-bot
Copy link
Contributor

Thanks for your pull request, @CyberShadow!

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + phobos#10894"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants