Ruby Language
Нить
Поиск…
Семантика основной темы
Новый поток, отдельный от выполнения основного потока, может быть создан с помощью Thread.new
.
thr = Thread.new {
sleep 1 # 1 second sleep of sub thread
puts "Whats the big deal"
}
Это автоматически запустит выполнение нового потока.
Чтобы заморозить выполнение основного потока, пока новый поток не остановится, используйте join
:
thr.join #=> ... "Whats the big deal"
Обратите внимание, что Thread, возможно, уже был завершен, когда вы вызываете join, и в этом случае выполнение будет продолжаться в обычном режиме. Если подпоток никогда не соединяется, а основной поток завершается, подпоток не будет выполнять какой-либо оставшийся код.
Доступ к общим ресурсам
Используйте мьютекс для синхронизации доступа к переменной, к которой обращаются из нескольких потоков:
counter = 0
counter_mutex = Mutex.new
# Start three parallel threads and increment counter
3.times.map do |index|
Thread.new do
counter_mutex.synchronize { counter += 1 }
end
end.each(&:join) # Wait for all threads to finish before killing the process
В противном случае значение counter
видимого в данный момент одному потоку, может быть изменено другим потоком.
Пример без Mutex
(см., Например, Thread 0
, где Before
и After
отличаются более чем на 1
):
2.2.0 :224 > counter = 0; 3.times.map { |i| Thread.new { puts "[Thread #{i}] Before: #{counter}"; counter += 1; puts "[Thread #{i}] After: #{counter}"; } }.each(&:join)
[Thread 2] Before: 0
[Thread 0] Before: 0
[Thread 0] After: 2
[Thread 1] Before: 0
[Thread 1] After: 3
[Thread 2] After: 1
Пример с Mutex
:
2.2.0 :226 > mutex = Mutex.new; counter = 0; 3.times.map { |i| Thread.new { mutex.synchronize { puts "[Thread #{i}] Before: #{counter}"; counter += 1; puts "[Thread #{i}] After: #{counter}"; } } }.each(&:join)
[Thread 2] Before: 0
[Thread 2] After: 1
[Thread 1] Before: 1
[Thread 1] After: 2
[Thread 0] Before: 2
[Thread 0] After: 3
Как убить нить
Вы вызываете использование Thread.kill
или Thread.terminate
:
thr = Thread.new { ... }
Thread.kill(thr)
Завершение темы
Поток заканчивается, если он достигает конца своего кодового блока. Лучший способ прервать поток на раннем этапе - убедить его достичь конца своего кодового блока. Таким образом, поток может запускать код очистки перед смертью.
Этот поток запускает цикл, пока переменная экземпляра continue имеет значение true. Установите эту переменную в значение false, и нить умрет естественной смертью:
require 'thread'
class CounterThread < Thread
def initialize
@count = 0
@continue = true
super do
@count += 1 while @continue
puts "I counted up to #{@count} before I was cruelly stopped."
end
end
def stop
@continue = false
end
end
counter = CounterThread.new
sleep 2
counter.stop