简体   繁体   中英

Ruby Thread local variables

Ruby has native support for thread local variables since version 2.0 . However active_support/core_ext/thread.rb implements this feature in pure ruby for support of thread locals in earlier versions of Ruby. So, I wonder why should we use mutex in _locals method:

https://github.com/rails/rails/blob/ec1227a9cc682ebf796689ef0f329038162c421b/activesupport/lib/active_support/core_ext/thread.rb#L76

_locals does two things:

def _locals
  # 1. Returns the local variable hash when defined
  if defined?(@_locals)
    @_locals

  # 2. Lazily instantiates a locals hash
  else
    LOCK.synchronize { @_locals ||= {} }
  end
end

That synchronization step is required to ensure that the @_locals is never cleared out during first access.

Consider the following scenario:

thread = Thread.new

# Say I run this statement...
thread.thread_variable_set('a', 1)

# In parallel with this statement...
thread.thread_variable_get(:a)

Both of those methods call _locals , and if they execute simultaneously, they may both end up at the lazy assignment step:

@_locals ||= {}
# Expands to...
unless @_locals
  @_locals = {}  # <-- We could end up here with both threads at the same time,
end              #     which jeopardizes any value that might have been set.

So imagine we had no mutex and that the setter completed execution while the getter had entered the lazy assignment step. We've effectively lost any locals we set due to a thread collision. Calling synchronize on a mutex guarantee that the block executes to completion without any such collisions.

Note that the core extension will not be loaded for versions of Ruby which support accessing thread-local variables. See the very last line:

unless Thread.instance_methods.include?(:thread_variable_set)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM