# Desafios com o uso de threads

O uso de threads, apesar de ser mais leve que forking de processos, traz também alguns desafios. A criação da thread `pthread_create` tem um custo no sistema operacional, como podemos imaginar. O join também, e o `pthread_mutex_lock` e unlock não ficam de fora.

Todas essas chamadas de funções com relação ao uso de threads causam um overhead no sistema como um todo, faz o escalonador trabalhar mais através de múltiplas **trocas de contexto,** e isso contribui para o aumento da latência total do sistema. Essa troca de contexto é custosa, pois envolve salvar e restaurar o estado da thread (registradores, pilha, etc) e pode causar **cache misses** no processador.

O sistema operacional implementa diversas otimizações para gerenciar threads de forma eficiente, mas mesmo assim, o uso indiscriminado pode levar a problemas de desempenho e complexidade.

> Trabalhar com threads é complexo

## Quando usar threads com cautela?

Criar muitas threads em um sistema com recursos limitados pode causar degradação de desempenho devido ao aumento do overhead de gerenciamento das threads.

Por exemplo, em um sistema com 4 núcleos de CPU, criar **centenas de threads** geralmente não traz ganho adicional, pois a maioria delas ficará em espera devido a *sincronização com mutexes*. Múltiplas trocas de contexto irão piorar ainda mais o desempenho.

Para além de **race conditions**, podemos também enfrentar problemas muito difíceis como **deadlocks,** que são comuns em sistemas multithreaded e difíceis de depurar.

<figure><img src="/files/XqKWw2arnD5H5LLnwrvF" alt="" width="258"><figcaption><p>exemnplo de deadlock na vida real kkk</p></figcaption></figure>

> Em algumas situações, como por exemplo quando a T1 tem o acesso ao mutex, mas por algum motivo esse mutex ficou perdido na memória, então ela não consegue recuperar o mutex e portanto o recurso fica bloqueado para todas as outras threads, que estão à espera. Este efeito causa um **deadlock**, que lança um erro fatal no programa que o faz terminar imediatamente.

Por último, o sistema operacional determina uma **quantidade limitada de threads.** Isto por si só já nos limita bastante se precisarmos de disparar milhares de threads, como no caso de requisições HTTP em um web server. Este limite pode ser definido pelo utilitário `ulimit` em sistemas UNIX-like, e é configurado tanto a nível de usuário quanto de processo.

Todas estas limitações nos levam a:

* criar uma abstração de "pool" (ou piscina), onde múltiplas threads **previamente criadas** podem ser utilizadas e devolvidas ao pool, assim não precisamos criar milhares de threads indiscriminadamente;
* recorrer a alternativas "thread-safe", que garantem de alguma forma que a memória não é compartilhada entre as threads; ou
* implementar um mecanismo de "green threads", onde pequenas unidades de concorrência vivem dentro do runtime (implementação), e não necessariamente no sistema operacional. Isto requer a implementação de um escalonador para essas green threads

Vamos primeiramente abordar a implementação de uma **pool de threads** e como isto pode mitigar bastante os problemas inerentes ao uso de threads.


---

# 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/desafios-com-o-uso-de-threads.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.
