# С другой стороны, присваивание создает новый объект,
# поэтому 'сокращение' становится бесполезным...
end
а = thread[:my_message] # 'hidden'
Ясно, что сокращение не будет работать и в том случае, когда вы имеете дело с объектами наподобие Fixnum
, которые хранятся как непосредственные значения, а не ссылки.
13.1.3. Опрос и изменение состояния потока
В классе Thread
есть несколько полезных методов класса. Метод list
возвращает массив «живых» потоков, метод main
возвращает ссылку на главный поток программы, который породил все остальные, а метод current
позволяет потоку идентифицировать самого себя.
t1 = Thread.new { sleep 100 }
t2 = Thread.new do
if Thread.current == Thread.main
puts 'Это главный поток.' # HE печатается,
end
1.upto(1000) { sleep 0.1 }
end
count = Thread.list.size # 3
if Thread.list.include ?(Thread.main)
puts 'Главный поток жив.' # Печатается всегда!
end
if Thread.current == Thread.main
puts 'Я главный поток.' # Здесь печатается...
end
Методы exit
, pass
, start
, stop
и kill
служат для управления выполнением потоков (как изнутри, так и извне):
# в главном потоке...
Thread.kill(t1) # Завершить этот поток.
Thread.pass # Передать управление t2.
t3 = Thread.new do
sleep 20
Thread.exit # Выйти из потока.
puts 'Так не бывает!' # Никогда не выполняется.
end
Thread.kill(t2) # Завершить t2.
# Выйти из главного потока (все остальные тоже завершаются).
Thread.exit
Отметим, что не существует метода экземпляра stop
, поэтому поток может приостановить собственное выполнение, но не выполнение другого потока.
Существуют различные методы для опроса состояния потока. Метод экземпляра alive?
сообщает, является ли данный поток «живым» (не завершил выполнение), а метод stop?
— находится ли он в состоянии «приостановлен».
count = 0
t1 = Thread.new { loop { count += 1 } }
t2 = Thread.new { Thread.stop }
sleep 1
flags = [t1.alive?, # true
t1.stop?, # false
t2.alive?, # true
t2.stop?] # true
Получить состояние потока позволяет метод status
. Он возвращает значение 'run'
, если поток выполняется; 'sleep'
— если он приостановлен, спит или ожидает результата ввода/вывода; false
— если поток нормально завершился, и nil
— если поток завершился в результате исключения.
t1 = Thread.new { loop {} }
t2 = Thread.new { sleep 5 }
t3 = Thread.new { Thread.stop }
t4 = Thread.new { Thread.exit }
t5 = Thread.new { raise 'exception' }
s1 = t1.status # 'run'
s2 = t2.status # 'sleep'
s3 = t3.status # 'sleep'
s4 = t4.status # false
s5 = t5.status # nil
Глобальную переменную $SAFE
можно установить по-разному в разных потоках. Стало быть, она вовсе не является глобальной, но стоит ли жаловаться на это, если она позволяет разным потокам работать с разным уровнем безопасности? Метод safe_level
возвращает текущий уровень безопасности потока.
t1 = Thread.new { $SAFE = 1; sleep 5 }
t2 = Thread.new { $SAFE = 3; sleep 5 }
sleep 1
lev0 = Thread.main.safe_level # 0
lev1 = t1.safe_level # 1
lev2 = t2.safe_level # 3
Метод доступа priority
позволяет узнать и изменить приоритет потока:
t1 = Thread.new { loop { sleep 1 } }
t2 = Thread.new { loop { sleep 1 } }
t2.priority = 3 # Установить для потока t2 приоритет 3
p1 = t1.priority # 0
p2 = t2.priority # 3
Поток с большим приоритетом будет чаще получать процессорное время. Специальный метод pass
позволяет передать управление планировщику. Иными словами, поток просто уступает свой временной квант, но не приостанавливается и не засыпает.
t1 = Thread.new do
puts 'alpha'
Thread.pass
puts 'beta'
end
t2 = Thread.new do
puts 'gamma'
puts 'delta'
end