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.

13.2.6. Тайм-аут при выполнении операций

Часто встречается ситуация, когда на выполнение операции отводится определенное максимальное время. Это позволяет избежать бесконечных циклов и более строго контролировать порядок работы. Подобная возможность очень полезна, в частности, в сетевых приложениях, где ответ от сервера может и не прийти.

Библиотека timeout.rb предлагает решение этой проблемы на основе потоков (см. листинг 13.6). С методом timeout ассоциирован выполняемый блок. Если истечет заданное число секунд, метод возбуждает исключение TimeoutError, которое можно перехватить с помощью rescue.

Листинг 13.6. Пример тайм-аута

require 'timeout.rb'

flag = false

answer = nil

begin

 timeout(5) do

  puts 'Хочу печенье!'

  answer = gets.chomp

  flag = true

 end

 rescue TimeoutError

 flag = false

end

if flag

 if answer == 'cookie'

  puts 'Спасибо! Хрум, хрум...'

 else

  puts 'Это же не печенье!'

  exit

 end

else

 puts 'Эй, слишком медленно!'

 exit

end

puts 'До встречи...'

13.2.7. Ожидание события

Часто один или несколько потоков следят за «внешним миром», а остальные выполняют полезную работу. Все примеры в этом разделе надуманные, но общий принцип они все же иллюстрируют.

В следующем примере прикладную задачу решают три потока. Четвертый поток каждые пять секунд просыпается, проверяет глобальную переменную $flag и, когда видит, что флаг поднят, пробуждает еще два потока. Это освобождает три рабочих потока от необходимости напрямую общаться с двумя другими и, возможно, от многочисленных попыток разбудить их.

$flag = false

work1 = Thread.new { job1() }

work2 = Thread.new { job2() }

work3 = Thread.new { job3() }

thread4 = Thread.new { Thread.stop; job4() }

thread5 = Thread.new { Thread.stop; job5() }

watcher = Thread.new do

 loop do

  sleep 5

  if $flag

   thread4.wakeup

   thread5.wakeup

   Thread.exit

  end

 end

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату