# 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://concorrencia101.leandronsp.com/parte-ii-concorrencia-em-diferentes-linguagens/concorrencia-em-ruby/forking-de-processos.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
