# Forking de processos

Vamos começar com um exemplo simples que imprime "Hello" na saída padrão:

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

```c
#include <stdio.h>

int main() {
	printf("Hello\n");
	return 0;
}
```

{% endcode %}

Primeiro passo é compilar o arquivo para um executável do SO:

```
$ gcc forking.c -o forking
```

Após isso, rodamos o executável e:

```
$ ./forking
Hello
```

> Dica: se quiser executar tudo em uma linha apenas, pode-se utilizar "gcc forking.c -o forking && ./forking"

*So far, so good.*

## O primeiro fork

Para fazer forking de processos em C, precisamos usar a syscall **fork** através do cabeçalho `unistd.h` (UNIX Standard), que fornece acesso a syscalls do Kernel, permitindo interagir diretamente com o sistema operacional:

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

```c
#include <stdio.h>
#include <unistd.h>

int main() {
	fork();
	printf("Hello\n");
	return 0;
}
```

{% endcode %}

```
Hello
Hello
```

E por quê vemos agora a mensagem sendo impressa duas vezes? O quê acontece quando chamamos **fork**? Vamos detalhar o fluxo do programa:

* o processo pai é iniciado no começo do programa; apenas o pai está em execução
* quando o `fork` é chamado, o sistema cria um novo processo filho, que é *uma cópia exata do processo pai,* incluindo o estado do programa naquele exato momento
* qualquer código depois do fork é executado tanto no processo pai quanto no processo filho; como ambos chamam a função "printf" com "Hello", então a mensagem é impressa 2 vezes

Um ponto a destacar aqui é que, no momento do fork, todos os file descriptors do pai (incluindo o **STDOUT**) foram herdados pelo filho, e é por isso que vemos a mensagem na mesma saída padrão (tela do terminal) 2 vezes.

> É possível fazer com que o filho tenha outra saída padrão diferente do pai, mas não vamos entrar nestes detalhes aqui, não importam muito para o assunto principal que é concorrência

Se quisermos que cada um imprima uma mensagem diferente, teríamos que saber , de alguma forma **após a chamada do fork**, se estamos dentro do processo pai ou do filho.

## Manual, o nosso melhor amigo

De acordo com o [manual](https://man7.org/linux/man-pages/man2/fork.2.html), a  syscall fork tem o seguinte retorno:

> ```
> On success, the PID of the child process is returned in the
>        parent, and 0 is returned in the child.  On failure, -1 is
>        returned in the parent, no child process is created, and  is
>        set to indicate the error.
> ```

Ou seja, dentro do filho, o retorno da função é `0` . E dentro do pai, o retorno é o PID do filho. Com isto, podemos ter o seguinte código:

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

```c
#include <stdio.h>
#include <unistd.h>

int main() {
	pid_t pid = fork();
	if (pid == 0) {
		printf("Hello from child\n");
	} else {
		printf("Hello from parent\n");
	}
	return 0;
}
```

{% endcode %}

Que se executado, tem a seguinte saída:

```
Hello from parent
Hello from child
```

*Yay!*

Mas repare que, devido à natureza preemptiva do escalonador, não temos controle sobre qual será executado primeiro. Poderia ser o pai, ou mesmo o filho.&#x20;

O que temos que entender aqui é que, **no momento do fork**, é criado um *novo processo* no sistema operacional, que irá competir por recursos junto a outros processos,  ou seja, todo mundo junto no mesmo balaio de concorrência.

## 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-complex.c" lineNumbers="true" %}

```c
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

void perform() {
	printf("Processo filho (PID: %d) executando tarefa...\n", getpid());
	sleep(2); // Simula uma tarefa que leva 2 segundos
	printf("Processo filho (PID: %d) completou a tarefa!\n", getpid());
}

int main() {
	int num_children = 3;
	pid_t pid;

	for (int i = 0; i < num_children; i++) {
		pid = fork(); // Cria um novo processo

		if (pid == 0) {
			// Processo filho
			perform();
			return 0;
		}
	}

	for (int i = 0; i < num_children; i++) {
		pid_t child_pid = wait(NULL); // Aguarda qualquer filho terminar
		printf("Pai: Processo filho com PID %d terminou.\n", child_pid);
	}

	printf("Pai: Todos os filhos terminaram. Finalizando.\n");
	return 0;
}
```

{% endcode %}

{% code lineNumbers="true" %}

```
Processo filho (PID: 271052) executando tarefa...
Processo filho (PID: 271053) executando tarefa...
Processo filho (PID: 271054) executando tarefa...
Processo filho (PID: 271052) completou a tarefa!
Processo filho (PID: 271053) completou a tarefa!
Pai: Processo filho com PID 271052 terminou.
Pai: Processo filho com PID 271053 terminou.
Processo filho (PID: 271054) completou a tarefa!
Pai: Processo filho com PID 271054 terminou.
Pai: Todos os filhos terminaram. Finalizando.
```

{% endcode %}

Interessante notar aqui:

* os 3 processos filhos foram criados e iniciaram sua execução (271052, 271053, 271054)
* 2 processos terminaram um pouco antes, sendo que o processo pai notificou que ambos tinham concluído execução
* um último processo (271054) terminou depois que o pai tinha notificado sobre os outros dois que concluíram primeiro
* o pai informa que todos os filhos foram concluídos e o programa finaliza

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)

Como processos não compartilham memória (a priori), precisamos de um mecanismo de comunicação entre processos, também chamado de **IPC** (Inter-process communication), pois um processo sem comunicação é bastante inútil.&#x20;

Uma das formas de IPC é através de **pipes,** que são uma comunicação *uni-direcional* entre processos.

> Se você quer entender mais sobre IPC e UNIX pipes, escrevi [um artigo sobre o tema](https://dev.to/leandronsp/entendendo-unix-pipes-3k56), onde é possível aprofundar nos conceitos de forma prática, e você só precisa de um terminal com shell/bash ou outra shell de preferência

```c
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main() {
    int pipe_fd[2];
    pid_t pid;

    pid = fork();

    if (pid == 0) {
        // Processo filho
        close(pipe_fd[0]); // Fecha a extremidade de leitura
        char mensagem[] = "Message from child!";
        // Escreve no pipe
        write(pipe_fd[1], mensagem, strlen(mensagem) + 1);
        close(pipe_fd[1]); // Fecha a extremidade de escrita
    } else {
        // Processo pai
        close(pipe_fd[1]); // Fecha a extremidade de escrita
        char buffer[100];
        // Lê a partir do pipe
        read(pipe_fd[0], buffer, sizeof(buffer));
        printf("Parent received message: %s\n", buffer);
        close(pipe_fd[0]); // Fecha a extremidade de leitura
    }

    return 0;
}
```

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

## Tá gostando do guia?

Se está gostando deste trabalho e considera fortalecer, o QRCode de PIX abaixo tá no jeito hein?

<figure><img src="/files/FUUkoZLpU19gvljXPbr1" alt="" width="283"><figcaption><p><br></p></figcaption></figure>

Ou copia a cola:

```
00020126850014BR.GOV.BCB.PIX013638ee4bde-574b-4197-b10f-68742087b00b0223Gratidão pelo cafezinho5204000053039865802BR5925Leandro Freitas Maringolo6009SAO PAULO62140510qrN6Ov1wRl63041A3C
```

***

Não vamos entrar em mais detalhes sobre uso de forking em C, isto já é o suficiente para o objetivo deste guia. No próximo tópico, iremos abordar o uso de **threads em C**.


---

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