Thread.stop doesn't end a thread, it merely pauses it. To end a thread, either return from the block, or call Thread.exit:
#!/usr/bin/ruby1.8
t = Thread.new do
Thread.exit
end
t.join
In the snippet from your question:
d = Thread.new{ Thread.stop }
d.join
the thread runs automatically; no call to Thread.run is necessary for the thread to start. However, the thread stops itself, which is not the same as the thread exiting: the thread needs only a call to Thread#run to start it running again. When the main thread calls Thread#join, the main thread stops being runnable. The interpreter looks for another thread to run, but the only other thread isn't runnable either. Ruby declares defeat and tells you, in a roundabout way, that it doesn't have any executable threads.
This code does not exhibit the deadlock most of the time, but contains a race condition:
d = Thread.new{ Thread.stop }
d.run
d.join
When it works, it's because Thread.stop happened before Thread#run. However, if Thread#run happens first, then Thread.stop will be waiting forever for a Thread#run that will never again happen. The result, once again, is that no threads are available to run:
t = Thread.new do
10000000.times {}
Thread.stop
end
t.run
t.join
# > deadlock 0xb7b47320: sleep:- - /tmp/foo.rb:5
# > deadlock 0xb7dcb1b4: sleep:J(0xb7b47320) (main) - /tmp/foo.rb:8
# > /tmp/foo.rb:8:in `join': Thread(0xb7dcb1b4): deadlock (fatal)
# > from /tmp/foo.rb:8