concorrencia101
  • Introdução
  • First things first
  • Agradecimentos
  • Parte I - Concorrência no sistema operacional
    • O que é o programa no sistema operacional
    • Escalonador preemptivo de tarefas
    • Uma nota sobre escalonamento cooperativo
    • Propriedades de um processo
    • Clone de processo (forking)
    • Clone leve de processo (thread)
    • Todo processo tem uma thread principal
    • Uma nota sobre paralelismo
    • Principais desafios em cenário de concorrência
      • Race condition
      • Sincronização com locks
      • Modelo de atores
    • E o I/O?
      • Latência de CPU vs Latência de I/O
      • Chamadas bloqueantes
      • Chamadas não-bloqueantes
      • Assincronismo e escalonamento cooperativo
    • Vamos colocar em prática...
  • PARTE II - Concorrência em diferentes linguagens
    • Definindo ambientes de execução
    • Concorrência em C
      • Forking de processos
      • Threads
      • Race condition e sincronização de threads com mutex
      • Desafios com o uso de threads
      • Thread Pool em C
      • Green threads
      • Modelo de Atores
      • Trabalhando com I/O
    • Concorrência em Ruby
      • Forking de processos
      • Threads
      • Race condition, YARV, GVL e paralelismo em Ruby
      • Modelo de Atores
      • Trabalhando com I/O
Powered by GitBook
On this page
  1. PARTE II - Concorrência em diferentes linguagens
  2. Concorrência em Ruby

Threads

PreviousForking de processosNextRace condition, YARV, GVL e paralelismo em Ruby

Last updated 4 months ago

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.

através da classe Thread.