Agora que entendemos como funciona o forking de processos, vamos explorar as threads. Threads são uma forma mais leve de concorrência, permitindo que múltiplas tarefas sejam executadas dentro do mesmo processo, compartilhando o mesmo espaço de memória.
Conforme explicado no módulo de C, conseguimos criar POSIX Threads através da chamada de função pthread_create. Na linguagem Ruby, conseguimos manipular kernel threads
# Função que será executada pela thread
def handle
puts "Hello from thread!"
end
# Cria uma thread
thread = Thread.new do
handle
end
puts "Hello from main thread!"
# Aguarda a thread terminar
thread.join
Hello from main thread!
Hello from thread!
Simples, não? Podíamos também passar qualquer código Ruby pra dentro do bloco da thread, não precisa ser necessariamente um método:
# Cria uma thread
thread = Thread.new do
puts "Hello from thread!"
end
puts "Hello from main thread!"
# Aguarda a thread terminar
thread.join
Um exemplo mais robusto
Agora vamos fazer um exemplo mais complexo com threads, assim como fizemos com forking de processos:
def handle(thread_id)
puts "Thread #{thread_id} is running..."
sleep(2) # Simula uma tarefa que leva 2 segundos
puts "Thread #{thread_id} is finished."
end
threads = []
# Criação das threads
3.times do |i|
threads << Thread.new(i + 1) do |thread_id|
handle(thread_id) # Passa o ID da thread como argumento
end
end
# Aguarda todas as threads finalizarem
threads.each_with_index do |thread, i|
thread.join
puts "Thread #{i + 1} has been finished."
end
puts "All threads are finished."
Thread 1 is running...
Thread 2 is running...
Thread 3 is running...
Thread 1 is finished.
Thread 3 is finished.
Thread 2 is finished.
Thread 1 has been finished.
Thread 2 has been finished.
Thread 3 has been finished.
All threads are finished.
Ruby dispensa comentários, não?
Vamos agora ver como Ruby resolve problemas de race condition.