Чтение онлайн

на главную - закладки

Жанры

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

 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} " # Может быть напечатано 7 или 8!

Здесь имеется проблема. Если ваша система ведет себя примерно так же, как наша, то программа может напечатать одно из двух значений! В наших тестах с одинаковой вероятностью печаталось 7 или 8. Если слов и списков больше, то и разброс окажется более широким.

Попробуем исправить положение с помощью мьютекса, который будет контролировать доступ к разделяемому ресурсу. (Слово «mutex» — это сокращение от mutual exclusion, «взаимная блокировка».)

Обратимся к листингу 13.2. Библиотека

Mutex
позволяет создавать мьютексы и манипулировать ими. Мы можем захватить (lock) мьютекс перед доступом к хэшу и освободить (unlock) его по завершении операции.

Листинг 13.2. Программа индексирования с мьютексом

require 'thread.rb'

@list = []

@list[0]="shoes ships\nsealing-wax"

@list[1]="cabbages kings"

@list[2]="quarks\nships\ncabbages"

def hesitate

 sleep rand(0)

end

@hash = {}

@mutex = Mutex.new

def process_list(listnum)

 lnum = 0

 @list[listnum].each do |line|

words = line.chomp.split

words.each do |w|

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, позволяющий получить и установить максимальный размер очереди.

Поделиться:
Популярные книги

Том 14. Критические статьи, очерки, письма

Гюго Виктор
14. Собрание сочинений
Документальная литература:
критика
публицистика
5.00
рейтинг книги
Том 14. Критические статьи, очерки, письма

Каменный град

Инин Дмитрий
3. Негодяй Аллара
Фантастика:
фэнтези
рпг
5.00
рейтинг книги
Каменный град

Точка Бифуркации VII

Смит Дейлор
7. ТБ
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Точка Бифуркации VII

СССР — Империя Добра

Кремлев Сергей
Научно-образовательная:
история
политика
6.25
рейтинг книги
СССР — Империя Добра

Хроника

Саксон Анналист
Mediaevalia: средневековые литературные памятники и источники
Научно-образовательная:
история
5.00
рейтинг книги
Хроника

Властитель темных небес

Синклер Шериз
3. Властители Тёмных Небес
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Властитель темных небес

"Фантастика 2023-121". Компиляция. Книги 1-25

Башибузук Александр
Фантастика 2023. Компиляция
Фантастика:
фэнтези
боевая фантастика
5.00
рейтинг книги
Фантастика 2023-121. Компиляция. Книги 1-25

Жизнь и удивительные приключения Нурбея Гулиа - профессора механики

Никонов Александр Петрович
Документальная литература:
биографии и мемуары
публицистика
5.75
рейтинг книги
Жизнь и удивительные приключения Нурбея Гулиа - профессора механики

Сила монстров

Чейз Ева
2. Тенекровные
Фантастика:
городское фэнтези
зарубежная фантастика
ужасы и мистика
5.00
рейтинг книги
Сила монстров

Потемкин

Елисеева Ольга Игоревна
916. Жизнь замечательных людей
Проза:
историческая проза
5.00
рейтинг книги
Потемкин

Геральт (сборник)

Сапковский Анджей
Фантастика:
героическая фантастика
5.00
рейтинг книги
Геральт (сборник)

Вечно голодный студент 8

RedDetonator
8. Вечно голодный студент
Фантастика:
боевая фантастика
постапокалипсис
рпг
фэнтези
фантастика: прочее
5.00
рейтинг книги
Вечно голодный студент 8

Они не люди. Книга третья

Фламмер Виктор
3. Они не люди
Фантастика:
детективная фантастика
городское фэнтези
5.00
рейтинг книги
Они не люди. Книга третья

Я все еще барон

Дрейк Сириус
4. Дорогой барон!
Фантастика:
боевая фантастика
5.00
рейтинг книги
Я все еще барон