45

If I have the following code :

threads = [] (1..5).each do |i| threads << Thread.new { `process x#{i}.bin` } end threads.each do |t| t.join # i'd like to get the output of the process command now. end 

What do I have to do to get the output of the process command? How could I create a custom thread so that I can accomplish this?

5 Answers 5

58

The script

threads = [] (1..5).each do |i| threads << Thread.new { Thread.current[:output] = `echo Hi from thread ##{i}` } end threads.each do |t| t.join puts t[:output] end 

illustrates how to accomplish what you need. It has the benefit of keeping the output with the thread that generated it, so you can join and get the output of each thread at any time. When run, the script prints

 Hi from thread #1 Hi from thread #2 Hi from thread #3 Hi from thread #4 Hi from thread #5 
Sign up to request clarification or add additional context in comments.

5 Comments

Vinay, maybe you can have a look at this too: stackoverflow.com/questions/1383470/…
Far nicer to simply return the output from the thread and use puts t.value
why threads do not interleave? Nothing like Hi Hi Hi from thread #1 from...
@Serge perhaps because of the GIL.
@Serge the output doesn't interleave because the printing itself is done serially. Note that the threads themselves don't print anything, all output is done in the loop at the end.
41

I found it simpler to use collect to collect the Threads into a list, and use thread.value to join and return the value from the thread - this trims it down to:

#!/usr/bin/env ruby threads = (1..5).collect do |i| Thread.new { `echo Hi from thread ##{i}` } end threads.each do |t| puts t.value end 

When run, this produces:

Hi from thread #1 Hi from thread #2 Hi from thread #3 Hi from thread #4 Hi from thread #5 

1 Comment

The one downside of this version relative to using Thread.current[:output] is that there is no way to have a timeout using value.
23

This is a simple, and interesting way to use Thread#value:

a, b, c = [ Thread.new { "something" }, Thread.new { "something else" }, Thread.new { "what?" } ].map(&:value) a # => "something" b # => "something else" c # => "what?" 

2 Comments

There is no need to call join because value does that internally.
Love this. Also, if one of your threads returns multiple values, you can still assign them by nesting assignments in parentheses e.g. a, (b, c), d =
3

Just use Thread#value:

threads = (1..5).collect do |i| Thread.new { `echo x#{i}.bin` } end threads.each do |t| puts t.value end 

Comments

3

You should use the Queue class. Each thread should put its result in the queue, and the main thread should fetch it from there. Notice that using that approach, results my be in a order different from thread creation order in the queue.

2 Comments

The Queue class is useful, but not necessary for the original poster's scenario, where there is no thread contention over a single value or collection of values. Therefore, thread locals suffice in this case.
Link is now broken.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.