Книга: Программирование на языке Ruby

13.2.3. Предопределенные классы синхронизированных очередей

13.2.3. Предопределенные классы синхронизированных очередей

В библиотеке thread.rb есть пара классов, которые иногда бывают полезны. Класс Queue реализует безопасную относительно потоков очередь, доступ к обоим концам которой синхронизирован. Это означает, что разные потоки могут, ничего не опасаясь, работать с такой очередью. Класс SizedQueue отличается от предыдущего тем, что позволяет ограничить размер очереди (число элементов в ней).

Оба класса имеют практически один и тот же набор методов, поскольку SizedQueue наследует Queue. Правда, в подклассе определен еще акцессор max, позволяющий получить и установить максимальный размер очереди.

buff = SizedQueue.new(25)
upper1 = buff.max #25
# Увеличить размер очереди...
buff.max = 50
upper2 = buff.max # 50

В листинге 13.3 приведено решение задачи о производителе и потребителе. Для производителя задержка (аргумент sleep) чуть больше, чем для потребителя, чтобы единицы продукции «накапливались».

Листинг 13.3. Задача о производителе и потребителе

require 'thread'
buffer = SizedQueue.new(2)
producer = Thread.new do
 item = 0
 loop do
  sleep rand 0
  puts "Производитель произвел #{item}"
  buffer.enq item
  item += 1
 end
end
consumer = Thread.new do
 loop do
  sleep (rand 0)+0.9
  item = buffer.deq
  puts "Потребитель потребил #{item}"
  puts " ожидает = #{buffer.num_waiting}"
 end
end
sleep 60 # Работать одну минуту, потом завершить оба потока.

Чтобы поместить элемент в очередь и извлечь из нее, рекомендуется применять соответственно методы enq и deq. Можно было бы для помещения в очередь пользоваться также методом push, а для извлечения — методами pop и shift, но их названия не так мнемоничны в применении к очередям.

Метод empty? проверяет, пуста ли очередь, а метод clear опустошает ее. Метод size (и его синоним length) возвращает число элементов в очереди.

# Предполагается, что другие потоки не мешают...
buff = Queue.new
buff.enq "one"
buff.enq "two"
buff.enq "three"
n1 = buff.size      # 3
flag1 = buff.empty? # false
buff.clear
n2 = buff.size      # 0
flag2 = buff.empty? # true

Метод num_waiting возвращает число потоков, ожидающих доступа к очереди. Если размер очереди не ограничен, то это потоки, ожидающие возможности удалить элементы; для ограниченной очереди включаются также потоки, пытающиеся добавить элементы.

Необязательный параметр non_block метода deq в классе Queue по умолчанию равен false. Если же он равен true, по при попытке извлечь элемент из пустой очереди он не блокирует поток, а возбуждает исключение ThreadError.

Оглавление книги


Генерация: 7.217. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз