Ruby Thread Locals are also Fiber-Local

I was briefly concerned that thread-local variables would not also be Fiber-local, since fibers have their own stack. This would be a problem for any code which uses thread-local variables to delimit a stack context, e.g. to implement dynamically-scoped variables or to prevent recursion. My fears, however, were easily allayed.

f = Fiber.new do
  puts "Fiber started"
  Thread.current[:in_fiber_context] = true
  Fiber.yield
  puts "Fiber-local value: #{Thread.current[:in_fiber_context].inspect}"
  puts "Fiber finished"
end

puts "Starting value: #{Thread.current[:in_fiber_context].inspect}"
f.resume
puts "Value outside of fiber: #{Thread.current[:in_fiber_context].inspect}"
f.resume
puts "Ending value: #{Thread.current[:in_fiber_context].inspect}"
# >> Starting value: nil
# >> Fiber started
# >> Value outside of fiber: nil
# >> Fiber-local value: true
# >> Fiber finished
# >> Ending value: nil

Once again, Ruby gets the little things right.

6 comments

  1. FWIW, I heard somewhere that this is MRI specific, and one of the other ruby implementations (maybe JRuby or Rubinius) implement fibers in a way that doesn’t make thread-locals also fiber-local.

    I don’t remember the details, though, unfortunately :(.

  2. I can see why they did it that way. At the same time, it’s surprising, and makes it tricky when you actually want state local to the Thread, rather than the Fiber. Which I did, earlier this year. I ended up having to ditch Thread-locals in favour of a Hash indexed by Thread.

  3. I think this is kind of awesome. It makes event-driven Ruby on Rails safe. By simply enabling Rails threadsafe mode and wrapping each request in a fiber, things like the session or IdentityMap in AR retain “fiber-safe” variables. I will admit it’s a little confusing due to the fact that a Fiber is supposed to run in a single Thread, but the result is awesome.

  4. It’s a little bit late, but it’s the first time I have read this post and fiber and threads are blowing a little my mind. I did read your post and rubies fiber and thread documentation.

    After reading the documentation I understand it in this way: Thread.current[] accesses only Fiber local variables. So with your last statement you are accessing in the last line the Fiber local variables of the root Fiber. If you realy want Thread local variables you have to use Thread.current.thread_variable_set(:in_fiber_context, true). With this you would have the same result in and outside the Fiber.

    Did I get it wrong or right?

Leave a Reply

Your email address will not be published. Required fields are marked *