6
votes

I want to call a common enumerator from different threads. When I do the following,

enum = (0..1000).to_enum
t1 = Thread.new do
  p enum.next
  sleep(1)
end
t2 = Thread.new do
  p enum.next
  sleep(1)
end
t1.join
t2.join

it raises an error:

Fiber called across threads.

when enum is called from t2 after once being called from t1.

  • Why is Ruby designed to not allow an enumerator (or fiber) to be called across threads, and
  • Is there an alternative way to provide a similar function?

I am guessing that atomicity of an operation on an enumerator/fiber is relevant here, but am not fully sure. If that is the issue, then exclusively-locking the enumerator/fiber while in use shall solve the problem, and I don't know why calling an enumerator/fiber across threads is prohibited in general. If an alternative can be provided by using locking, that would satisfy my need.

1
will a Queue satisfy your needs? - Uri Agassi
@UriAgassi If you can do it with it, it would. - sawa
@sawa, what did you end up doing? - Ismail Moghul

1 Answers

1
votes

You can use Queue

queue = Queue.new
(0..1000).map(&queue.method(:push))

t1 = Thread.new do
  while !queue.empty?
    p queue.pop(true)
    sleep(0.1)
  end
end
t2 = Thread.new do
  while !queue.empty?
    p queue.pop(true)
    sleep(0.1)
  end
end
t1.join
t2.join