Программирование на языке Ruby
Программирование на языке Ruby читать книгу онлайн
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
end
threads = []
3.times {|i| threads << Thread.new { musician(i) } }
threads.each {|t| t.join }
Мы полагаем, что это решение никогда не приводит к тупиковой ситуации, хотя доказать этого не сумели. Но интересно отметить, что описанный алгоритм не справедливый. В наших тестах оказалось, что первый скрипач играет чаще двух остальных, а второй чаще третьего. Выяснение причин такого поведения и его исправление мы оставляем читателю в качестве интересного упражнения.
13.2.5. Другие способы синхронизации
Еще один механизм синхронизации - это монитор, который в Ruby реализован в библиотеке
monitor.rb
Тривиальный случай возникновения такой ситуации вряд ли возможен. В самом деле, кто станет писать такой код:
@mutex = Mutex.new
@mutex.synchronize do
@mutex.synchronize do
#...
end
end
Но нечто подобное может произойти в сложной программе (или при рекурсивном вызове метода). Какова бы ни была причина, последствием будет тупиковая ситуация. Уход от нее — одно из достоинств модуля-примеси
Monitor
@mutex = Mutex.new
def some_method
@mutex.synchronize do
#...
some_other_method # Тупиковая ситуация!
end
end
def some_other_method
@mutex.synchronize do
#...
end
end
Модуль-примесь
Monitor
new_cond
Класс
ConditionVariable
monitor.rb
thread
wait_until
wait_while
wait
timeout
nil
Поскольку примеры работы с потоками у нас кончаются, то в листинге 13.5 мы предлагаем реализацию классов
Queue
SizedQueue
# Автор: Shugo Maeda
require 'monitor'
class Queue
def initialize
@que = []
@monitor = Monitor.new
@empty_cond = @monitor.new_cond
end
def enq(obj)
@monitor.synchronize do
@que.push(obj)
@empty_cond.signal
end
end
def deq
@monitor.synchronize do
while @que.empty?
@empty_cond.wait
end
return @que.shift
end
end
end
class SizedQueue < Queue
attr :max
def initialize(max)
super()
@max = max
@full_cond = @monitor.new_cond
end
def enq(obj)
@monitor.synchronize do
while @que.length >= @max
@full_cond.wait
end
super(obj)
end
end
def deq
@monitor.synchronize do
obj = super
if @que.length < @max
@full_cond.signal
end
return obj
end
end
def max=(max)
@monitor.synchronize do
@max = max
@full_cond.broadcast
end
end
end
Еще один вариант синхронизации (двузначную блокировку со счетчиком) предлагает библиотека
sync.rb
Sync_m
include
extend
Mutex_m
locked?
shared?
exclusive?
lock
unlock
try_lock