2

I'm trying to figure out a good way to wait for all threads to be executed before the main thread finishes.

How can I do that in the following code?

    threads = []

    counter = 1000

    lines = 0

    counter.times do |i|
      puts "This is index number #{i}."
    end

    puts "You've just seen the normal printing and serial programming.\n\n"

    counter.times do |i|
      Thread.new do
        some_number = Random.rand(counter)
        sleep 1
        puts "I'm thread number #{i}. My random number is #{some_number}.\n"
        lines += 1
      end
    end

    messaged = false
    while lines < 1000
      puts "\nWaiting to finish.\n" unless messaged
      print '.'
      puts "\n" if lines == 1000
      messaged = true
    end

    puts "\nI've printed #{lines} lines.\n"
    puts "This is end of the program."

The program puts the I'm thread number XXX. My random number is YYY mixed with the dots from the while loop almost at the end of the main thread. If I don't use the while loop, the program finishes before the threads finish.

Thanks for all the fish
  • 1,671
  • 3
  • 17
  • 31

2 Answers2

3

To make the parent wait for the children to finish, you use join

 threads = []
 counter.times do |i|
    thr = Thread.new do
            some_number = Random.rand(counter)
            sleep 1
            puts "I'm thread number #{i}. My random number is #{some_number}.\n"
            lines += 1
    end
    threads << thr
  end
  threads.each {|thread| thread.join }
Ludovico Fischer
  • 1,602
  • 11
  • 11
  • Should I add the thr inside of the counter.time loop? Then I use thr.join out side for each thread? – Thanks for all the fish Aug 22 '12 at 13:18
  • You need to join each thread that you created. So add the assignment to the thr variable inside the loop, then call join on it just before exiting each loop iteration. – Ludovico Fischer Aug 22 '12 at 13:37
  • I tried this: counter.times do |i| thr = Thread.new do some_number = Random.rand(counter) sleep 1 puts "I'm thread number #{i}. My random number is #{some_number}.\n" lines += 1 end thr.join end Now, the code instead of running multi-thread, it serializes the process again. I have to wait each thread to sleep for 1 second instead of having all of them doing it concurrently. – Thanks for all the fish Aug 22 '12 at 14:01
  • Ah yes, woops, you need to create all the thread before joining. Instead of calling join immediately, create an array before the loop that creates the thread and add each newly created thread to the array. After you exit the loop, join each thread in the array. – Ludovico Fischer Aug 22 '12 at 14:38
1

You need to keep a reference to the threads so you can 'join' them. Something like:

counter.times.map do |i|
  Thread.new do
    # thread code here
  end
end.each{|t| t.join}
pguardiario
  • 53,827
  • 19
  • 119
  • 159