> 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-c/green-threads.md).

# Green threads

Quando falamos de **threads**, geralmente estamos nos referindo a *threads do sistema operacional*, ou **kernel threads**. Algumas implementações de linguagens de programação, como o *GCC em C*, permitem utilizar kernel threads, que no caso do C é através da função `pthread_create` .

Mas como vimos no tópico sobre os desafios com o uso de kernel threads, a gestão de milhares de threads pode aumentar consideravelmente a latência do sistema.

Como alternativa, algumas implementações optam por usar abstrações similar a threads dentro do próprio runtime, pelo que precisam desenvolver o próprio escalonador de threads.&#x20;

A essas threads que vivem dentro do runtime, ou como costumamos dizer, *a nível do usuário*, damos o nome de **green threads**.

Mas antes de falarmos das green threads, vamos relembrar o funcionamento de uma kernel thread.

## Funcionamento de uma kernel thread

Como já aprendemos nos tópicos anteriores, em C conseguimos criar threads do sistema operacional, ou kernel threads. Basicamente, uma kernel thread tem uma pilha onde guarda o estado de execução entre outros metadados:

<figure><img src="/files/DaoxIFp224I8OYOMPhWt" alt="" width="563"><figcaption></figcaption></figure>

Em C, a chamada da função `pthread_create` basicamente cria uma kernel thread, então a gestão de escalonamento e troca de contexto fica completamente a cargo do kernel (SO), e não do GCC:

<figure><img src="/files/Mtv69zCfLtmU3hp16kTV" alt="" width="563"><figcaption></figcaption></figure>

## Como funciona uma green thread

Uma green thread geralmente tem uma estrutura similar a uma kernel thread, contendo sua própria pilha de memória mas compartilhando a memória principal do processo.&#x20;

Mas uma green thread tem a vantagem de não levar com a latência da criação de kernel threads, ou seja, dependendo da *implementação de green threads no runtime*, podemos criar milhares, senão **milhões de green threads** mantendo baixa latência.

A nível de implementação, em determinado momento vamos precisar "associar" as green threads às kernel threads, afinal:

> Todo programa roda em uma thread principal, ou seja, para o escalonador do sistema operacional é *tudo thread*, ou melhor ainda, **é tudo task**

O desafio é então *multiplexar* um número arbitrário de green threads para kernel threads, e isto pode ser feito de várias formas. Vamos a seguir detalhar alguns tipos comuns de implementação de green threads.

### 1. Uma kernel thread, múltiplas green threads

Neste tipo de implementação, temos apenas uma thread principal do programa que é mapeada diretamente para uma kernel thread. E dentro desta thread, criamos múltiplas green threads:

<figure><img src="/files/VItrrvCskqNkwGpCOJio" alt="" width="563"><figcaption></figcaption></figure>

A vantagem desta abordagem é que temos **menos latência** comparando com o uso indiscriminado de kernel threads, mas por outro lado, a desvantagem é que **não temos um paralelismo real** mesmo em CPU multi-core, pois o sistema operacional não sabe que se trata de uma green thread, então no fim das contas é apenas **uma thread** sendo utilizada na CPU.

### 2. Multiplexação de N green threads para M kernel threads

Esta abordagem é muito comum no runtime Go, e é basicamente a capacidade de criar uma kernel thread para um conjunto específico de green threads:

<figure><img src="/files/n3gdAYDvuxGSBPbgBheP" alt="" width="563"><figcaption></figcaption></figure>

A vantagem nisso é que podemos utilizar mais paralelismo, uma vez que cada kernel thread pode utilizar um núcleo de CPU. Se o runtime for espertinho o suficiente, temos uma situação muito interessante para lidar com concorrência e paralelismo.

> Alô Gophers, o momento de vocês está chegando :P

### 3. Múltiplos escalonadores

Outra abordagem muito interessante, e que é utilizada na implementação do Erlang/Elixir (BEAM), é que poderíamos multiplexar kernel threads pra cada escalonador. Assim, cada escalonador iria cuidar de um número X de *green threads* mantendo o paralelismo real.

<figure><img src="/files/Rpfb0udECxuROvEwumaG" alt=""><figcaption></figcaption></figure>

Mas a ideia por enquanto não é falar de Go nem Erlang, pois estamos ainda no C. Chegou o momento de entender como podemos trabalhar com green threads em C.

## Green threads em C

Infelizmente, a implementação padrão do GCC não traz suporte a green threads. O que até faz sentido, imagina o C trazer isso? Seria overkill, sendo uma linguagem bastante genérica, de propósito geral e muito perto do sistema operacional.

Mas há algumas bibliotecas externas que trazem este conceito, onde podemos ter "green threads" em C contando com uma estrutura de escalonamento das threads:

* [libdill.org](https://libdill.org/): green threads (chamadas na lib de **corrotinas**), com comunicação baseada em canais e escalonamento cooperativo
* [libmill.org](https://libmill.org/): similar à libdill, mas implementada de forma mais robusta e escalável, com multiplexing de kernel threads semelhante ao que temos em Go
* ...entre outras, como libtask, libcoro, GNU pth etc
