класс ActiveSupport::Concurrency::ShareLock
Блокировка по принципу совместного доступа/исключительного доступа, также известная как блокировка чтение/запись.
Открытые методы класса
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 50
def initialize
super()
@cv = new_cond
@sharing = Hash.new(0)
@waiting = {}
@sleeping = {}
@exclusive_thread = nil
@exclusive_depth = 0
end Открытые методы экземпляра
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 148
def exclusive(purpose: nil, compatible: [], after_compatible: [], no_wait: false)
if start_exclusive(purpose: purpose, compatible: compatible, no_wait: no_wait)
begin
yield
ensure
stop_exclusive(compatible: after_compatible)
end
end
end Выполняет предоставленный блок, удерживая эксклюзивную блокировку. Если no_wait установлено и блокировка не доступна немедленно, возвращает nil, не отдавая управление. В противном случае возвращает результат блока.
См. start_exclusive для других вариантов.
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 159
def sharing
start_sharing
begin
yield
ensure
stop_sharing
end
end Выполняет предоставленный блок, удерживая блокировку совместного доступа.
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 76
def start_exclusive(purpose: nil, compatible: [], no_wait: false)
synchronize do
unless @exclusive_thread == Thread.current
if busy_for_exclusive?(purpose)
return false if no_wait
yield_shares(purpose: purpose, compatible: compatible, block_share: true) do
wait_for(:start_exclusive) { busy_for_exclusive?(purpose) }
end
end
@exclusive_thread = Thread.current
end
@exclusive_depth += 1
true
end
end Возвращает false, если no_wait установлено и блокировка не доступна немедленно. В противном случае возвращает true после получения блокировки.
purpose и compatible работают вместе; в то время как этот поток ожидает эксклюзивную блокировку, он отдаст свои общие блокировки (если таковые имеются) любой другой попытке, чья purpose появляется в списке compatible этой попытки. Это позволяет «рыхлое» обновление, которое, будучи менее строгим, предотвращает некоторые классы тупиков.
Для многих ресурсов рыхлые обновления достаточно: если поток ожидает блокировку, он не выполняет никакой другой код. С помощью purpose сопоставления возможно отдавать управление только другим потокам, чья активность не будет мешать.
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 114
def start_sharing
synchronize do
if @sharing[Thread.current] > 0 || @exclusive_thread == Thread.current
# We already hold a lock; nothing to wait for
elsif @waiting[Thread.current]
# We're nested inside a +yield_shares+ call: we'll resume as
# soon as there isn't an exclusive lock in our way
wait_for(:start_sharing) { @exclusive_thread }
else
# This is an initial / outermost share call: any outstanding
# requests for an exclusive lock get to go first
wait_for(:start_sharing) { busy_for_sharing?(false) }
end
@sharing[Thread.current] += 1
end
end # File activesupport/lib/active_support/concurrency/share_lock.rb, line 96
def stop_exclusive(compatible: [])
synchronize do
raise "invalid unlock" if @exclusive_thread != Thread.current
@exclusive_depth -= 1
if @exclusive_depth == 0
@exclusive_thread = nil
if eligible_waiters?(compatible)
yield_shares(compatible: compatible, block_share: true) do
wait_for(:stop_exclusive) { @exclusive_thread || eligible_waiters?(compatible) }
end
end
@cv.broadcast
end
end
end Освобождает эксклюзивную блокировку. Должна вызываться только потоком, который вызвал start_exclusive (и в настоящее время удерживает блокировку).
# File activesupport/lib/active_support/concurrency/share_lock.rb, line 131
def stop_sharing
synchronize do
if @sharing[Thread.current] > 1
@sharing[Thread.current] -= 1
else
@sharing.delete Thread.current
@cv.broadcast
end
end
end Временно отказывается от всех удерживаемых блокировок совместного доступа при выполнении предоставленного блока, позволяя любой compatible эксклюзивной просьбе блокировки продолжить работу.
© 2004–2020 David Heinemeier Hansson
Licensed under the MIT License.