> For the complete documentation index, see [llms.txt](https://concorrencia101.leandronsp.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://concorrencia101.leandronsp.com/parte-ii-concorrencia-em-diferentes-linguagens/concorrencia-em-ruby/forking-de-processos.md).

# Forking de processos

Para aqueles que já leram a [parte I do guia](https://concorrencia101.leandronsp.com/parte-i-concorrencia-no-sistema-operacional/o-que-e-o-programa-no-sistema-operacional), não terão qualquer dificuldade em entender os conceitos aqui abordados. E caso também você tenha **real interesse** em aprender sobre concorrência, certamente já leu como funciona [forking de processos em C](https://concorrencia101.leandronsp.com/parte-ii-concorrencia-em-diferentes-linguagens/concorrencia-em-c/forking-de-processos).

Em Ruby, existe um método especial chamado `fork` que, na hora de ser executado, faz a chamada de sistema *fork.*

Vamos ver o primeiro exemplo similar ao que vimos inicialmente no módulo de C:

{% code title="forking.rb" %}

```ruby
fork
puts "Hello"
```

{% endcode %}

Agora vamos executar o programa utilizando o interpretador CRuby chamando `ruby forking.rb` , que imprime:

```
Hello
Hello
```

So far, so good. Já vimos anteriormente o motivo de aparecer `Hello` 2 vezes. Em um outro exemplo, podemos ver que o pid é diferente dependendo se estamos no parent ou no child:

```ruby
pid = fork

if pid
  puts "In parent, pid is #{Process.pid}. Child is #{pid}"
else
  puts "In child, pid is #{Process.pid}"
end
```

```
In parent, pid is 77278. Child is 77430
In child, pid is 77430
```

> Leiam a [documentação](https://ruby-doc.org/core-3.0.0/Process.html#method-c-pid), sempre

## Um exemplo mais robusto

Agora, vamos a um exemplo um pouco mais robusto com o uso de fork de processos, onde um processo pai dispara 3 processos filhos que irão executar uma tarefa que demora 2 segundos cada:

{% code title="forking.rb" lineNumbers="true" %}

```ruby
def perform
  pid = Process.pid

  puts "Processo filho (PID: #{pid}) executando tarefa..."
  sleep(2) # Simula uma tarefa que leva 2 segundos
  puts "Processo filho (PID: #{pid}) completou a tarefa!"
end

wait_pids = []

# Criação dos processos filhos
3.times do
  pid = fork do
    perform # Código do processo filho
  end

  wait_pids << pid # Armazena o PID do filho para controle
end

# O processo pai aguarda cada filho terminar
wait_pids.each do |child_pid|
  Process.wait(child_pid)

  puts "Pai: Processo filho com PID #{child_pid} terminou."
end

puts "Pai: Todos os filhos terminaram. Finalizando."
```

{% endcode %}

```
Processo filho (PID: 78317) executando tarefa...
Processo filho (PID: 78319) executando tarefa...
Processo filho (PID: 78318) executando tarefa...
Processo filho (PID: 78318) completou a tarefa!
Processo filho (PID: 78317) completou a tarefa!
Processo filho (PID: 78319) completou a tarefa!
Pai: Processo filho com PID 78317 terminou.
Pai: Processo filho com PID 78318 terminou.
Pai: Processo filho com PID 78319 terminou.
Pai: Todos os filhos terminaram. Finalizando.
```

Interessante notar aqui:

* os 3 processos filhos foram criados e iniciaram sua execução nesta ordem (78317, 78318, 78319)
* entretanto, de acordo com as mensagens, o processo 78318 terminou antes dos outros 2
* mas para o processo pai, o filho que terminou primeiro foi o 78317

Isto, *senhoras e senhores*, é a maravilha da concorrência. Não temos controle algum sobre a ordem e execução das tarefas!

> Sim, vou repetir isso inúmeras vezes neste guia kk

## Comunicação entre processos (IPC)

Assim como em C, podemos fazer **IPC** em Ruby utilizando [pipes](https://ruby-doc.org/core-3.0.0/IO.html#method-c-pipe):

```ruby
# Cria um pipe com dois descritores (leitura e escrita)
read_fd, write_fd = IO.pipe

pid = fork do
  # Processo filho
  read_fd.close # Fecha a extremidade de leitura no filho
  mensagem = "Message from child!"
  write_fd.puts(mensagem) # Escreve a mensagem no pipe
  write_fd.close # Fecha a extremidade de escrita no filho
end

# Processo pai
write_fd.close # Fecha a extremidade de escrita no pai
mensagem_recebida = read_fd.gets.chomp # Lê a mensagem do pipe
puts "Parent received message: #{mensagem_recebida}"
read_fd.close # Fecha a extremidade de leitura no pai

# Aguarda o processo filho terminar
Process.wait(pid)
```

Este é um exemplo bastante simples de como 2 processos distintos podem conversar entre si, através da utilização de UNIX pipes.

Repare como que até o momento, conseguimos fazer em Ruby tudo o que foi possível fazer em C com relação a **forking de processos**, e isto se deve ao fato de que o interpretador CRuby é escrito em C, o que torna simples a interface para as syscalls envolvidas no sistema operacional.

Agora, chegou o momento de vermos as *Threads* em Ruby.
