Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread.join blocks the main thread

Calling Thread.join blocks the current (main) thread. However not calling join results in all spawned threads to be killed when the main thread exits. How does one spawn persistent children threads in Ruby without blocking the main thread?

Here's a typical use of join.

for i in 1..100 do
  puts "Creating thread #{i}"
  t = Thread.new(i) do |j|
    sleep 1
    puts "Thread #{j} done"
  end
  t.join
end
puts "#{Thread.list.size} threads"

This gives

     Creating thread 1  
     Thread 1 done  
     Creating thread 2  
     Thread 2 done  
     ...  
     1 threads  

but I'm looking for how to get this

    Creating thread 1  
    Creating thread 2  
    ...  
    101 threads  
    Thread 1 done  
    Thread 2 done  
    ...  

The code gives the same output in both Ruby 1.8.7 and 1.9.2

like image 900
Bernard Avatar asked Aug 14 '10 03:08

Bernard


People also ask

Does join block main thread?

Join is a synchronization method that blocks the calling thread (that is, the thread that calls the method) until the thread whose Join method is called has completed. Use this method to ensure that a thread has been terminated. The caller will block indefinitely if the thread does not terminate.

Why do threads get blocked?

A Blocked state will occur whenever a thread tries to acquire lock on object and some other thread is already holding the lock. Once other threads have left and its this thread chance, it moves to Runnable state after that it is eligible pick up work based on JVM threading mechanism and moves to run state.

What is blocking of thread?

Blocked means execution gets stuck there; generally, the thread is put to sleep by the system and yields the processor to another thread. When a thread is blocked trying to acquire a mutex, execution resumes when the mutex is released, though the thread might block again if another thread grabs the mutex before it can.

What does it mean to join threads?

Joining a thread means to wait for it to complete. That is, block the current thread until another completes.


1 Answers

You simply accumulate the threads in another container, then join them one-by-one after they've all been created:

my_threads = []
for i in 1..100 do
    puts "Creating thread #{i}"
    my_threads << Thread.new(i) do |j|
        sleep 1
        puts "Thread #{j} done"
    end
end
puts "#{Thread.list.size} threads"

my_threads.each do |t|
    t.join
end

You also can't bind the thread to the i variable because i gets constantly overwritten, and your output will be 100 lines of "Thread 100 done"; instead, you have to bind it to a copy of i, which I have cleverly named j.

like image 77
Mark Rushakoff Avatar answered Sep 25 '22 07:09

Mark Rushakoff