# Chamadas não-bloqueantes

O sistema operacional fornece um recurso muito interessante de chamadas não-bloqueantes em I/O. Desta forma, o programa recebe imediatamente um *file descriptor* que representa o I/O solicitado, e depois recorre a recursos do sistema operacional para verificar quando o recurso está pronto. Assim, o programa não fica bloqueado.

Esta é a definição de **assincronismo**, ou **I/O assíncrono**.

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

Em Linux, chamadas de sistema como **select** ou **epoll** permitem controlar I/O assíncrono. Com select o programa verifica quais descritores estão prontos, enquanto que no epoll, o SO notifica o programa através de uma fila quais descritores estão prontos.

> Também não vamos por enquanto entrar nos detalhes do uso de select ou epoll, isto fica numa seção futura neste guia quando entrarmos na parte de implementação. Aqui, é importante *entendermos os conceitos*.

De qualquer forma, o programa, seja ele qual for, não precisa usar multi-thread para lidar com I/O - a não ser que realmente queira. Com apenas uma thread, é possível criar um "loop" que fica verificando no SO quais chamadas ficaram prontas.

Vamos, em pseudocódigo, escrever um loop com este propósito:

```
fun main():
    # Lista de descritores de arquivos
    
    input_fds  = [fd1, fd2, fd3]  # Descritores para monitorar leitura
    output_fds = [fd4]            # Descritores para monitorar escrita
    error_fds  = []               # Descritores para monitorar erros

    while true:
        # Chama a função select e espera até que algum descritor esteja pronto
        ready_read, ready_write, ready_error = 
	        select(input_fds, output_fds, error_fds)

        # Verifica os descritores prontos para leitura
        for fd in ready_read:
            data = read(fd)
            print("Dados lidos de fd:", fd, "->", data)

        # Verifica os descritores prontos para escrita
        for fd in ready_write:
            write(fd, "Mensagem de teste")
            print("Dados escritos em fd:", fd)

        # Verifica os descritores com erro
        for fd in ready_error:
            print("Erro detectado no descritor:", fd)

```

Enfim, a ideia aqui é ilustrar como seria um **loop de eventos** hipotético, que tanto ouvimos falar:

* iniciar loop
* passar para o select (ou epoll) a lista de descritores que queremos monitorar
* ler os descritores que estão prontos para leitura
* escrever nos descritores que estão prontos para escrita
* repetir o loop infinitamente

Repare que, ao termos um loop assíncrono de eventos, é extremamente importante toda e qualquer chamada ser **não-bloqueante**, caso contrário, se tivermos ao menos uma chamada bloqueante, o loop todo ficará bloqueado, e consequentemente a thread ficará bloqueada.

> Lembrem-se, com I/O assíncrono nunca podemos bloquear o loop. Toda chamada no I/O deve ser assíncrona.


---

# 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-i-concorrencia-no-sistema-operacional/e-o-i-o/chamadas-nao-bloqueantes.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.
