hesitate

   @mutex.lock

   if @hash[w]

    hesitate

    @hash[w] += ['#{listnum}:#{lnum}']

   else

    hesitate

    @hash[w] = ['#{listnum}:#{lnum}']

   end

   @mutex.unlock

  end

  lnum += 1

 end

end

t1 = Thread.new(0) {|num| process_list(num) }

t2 = Thread.new(1) {|num| process_list(num) }

t3 = Thread.new(2) {|num| process_list(num) }

t1.join

t2.join

t3.join

count = 0

@hash.values.each {|v| count += v.size }

puts 'Всего слов: #{count} ' # Всегда печатается 8!

Отметим, что помимо метода lock в классе Mutex есть также метод try_lock. Он отличается от lock тем, что если мьютекс уже захвачен другим потоком, то он не дожидается освобождения, а сразу возвращает false.

require 'thread'

mutex = Mutex.new

t1 = Thread.new { mutex.lock; sleep 30 }

sleep 1

t2 = Thread.new do

 if mutex.try_lock

  puts 'Захватил'

 else

  puts 'He сумел захватить' # Печатается немедленно.

 end

end

sleep 2

Эта возможность полезна, если поток не хочет приостанавливать выполнение. Есть также метод synchronize, который захватывает мьютекс, а потом автоматически освобождает его.

mutex = Mutex.new

mutex.synchronize do

 # Любой код, нуждающийся в защите...

end

Существует еще библиотека mutex_m, где определен модуль Mutex_m, который можно подмешивать к классу (или использовать для расширения объекта). У такого расширенного объекта будут все методы мьютекса, так что он сам может выступать в роли мьютекса.

require 'mutex_m'

class MyClass

 include Mutex_m

 # Теперь любой объект класса MyClass может вызывать

 # методы lock, unlock, synchronize...

 # Внешние объекты также могут вызывать эти

 # методы для объекта MyClass.

end

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

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

0

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

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