Multithreading em C++

Sistemas concorrentes de máxima perfomance com controle total sobre recursos. C++ oferece controle total sobre threads, memória e sincronização. Sua experiência define os limites, não o compilador

Recursos

Recursos de Threading

std::thread

Criação básica de threads e gerenciamento com controle total sobre o ciclo de vida e execução. Permite iniciar tarefas em paralelo, controlar quando começam e terminam, e coordenar a execução de diferentes partes de um programa. Com std::thread, é possível criar aplicações mais responsivas e aproveitar melhor processadores com múltiplos núcleos.

std::async

Permite executar funções em segundo plano sem precisar gerenciar explicitamente threads, simplificando o código e reduzindo a possibilidade de erros. Ao utilizar std::async, é possível obter resultados de forma assíncrona por meio de objetos std::future, garantindo que o processamento pesado não bloqueie a execução principal do programa. É ideal para operações independentes que podem ser processadas em paralelo.

Sincronização

Mutexes, variáveis de condição e operações atômicas para programação thread-safe. A sincronização é essencial quando múltiplas threads acessam e modificam os mesmos recursos. Com ferramentas como std::mutex, std::condition_variable e operações atômicas (std::atomic), é possível coordenar o acesso, evitando conflitos e garantindo a integridade dos dados.

std::jthread

Uma versão melhorada no C++20 com limpeza automática e cancelamento cooperativo. std::jthread facilita o gerenciamento de threads ao encerrar automaticamente sua execução no destrutor, evitando esquecimentos e vazamentos de recursos. Além disso, oferece suporte integrado para cancelamento cooperativo por meio de std::stop_token, permitindo que threads sejam interrompidas de forma segura e previsível.Essa abordagem reduz a complexidade do código e torna a programação concorrente mais robusta e menos propensa a erros.

Corrotinas

Corrotinas do C++20 para multitarefa cooperativa leve e programação assíncrona. As corrotinas permitem pausar e retomar funções em pontos específicos, possibilitando a escrita de código assíncrono de forma mais clara e linear. Com o C++20, a linguagem oferece suporte nativo a esse recurso, facilitando a criação de pipelines de processamento, geradores de dados e sistemas de multitarefa leve. Diferente das threads tradicionais, corrotinas não exigem troca de contexto no nível do sistema operacional, tornando sua execução mais rápida e com menor consumo de recursos.

Thread Pools

Gerenciamento eficiente de recursos com worker threads reutilizáveis para melhor performance. Um thread pool é um conjunto de threads previamente criadas que permanecem disponíveis para executar múltiplas tarefas ao longo da vida útil do programa. Em vez de criar e destruir threads para cada operação , o thread pool reutiliza as mesmas threads, reduzindo a sobrecarga e melhorando a eficiência. Essa abordagem é ideal para aplicações que processam um grande número de tarefas curtas ou de média duração, garantindo melhor uso dos recursos do sistema e maior previsibilidade na execução.

Alguns Exemplos de Código

#include <thread>
#include <iostream>

using namespace trabalhador(int id) {
    std::cout << "Thread " << id << " trabalhando\n";
}

int main() {
    std::thread t1(trabalhador, 1);
    std::thread t2(trabalhador, 2);
    
    t1.join();
    t2.join();
    return 0;
}

Operações Assíncronas


#include <chrono>
#include <future>
#include <iostream>
using namespace std;

int returnTwo() { return 2; }

int main()
{
    // Criando um objeto futuro e a thread que executa
    // A função retorna dois de forma assíncrona
    future<int> f = async(launch::async, returnTwo);

    // Pegando e printando o resultado
    cout << f.get();

    return 0;
}

jthread Moderno (C++20)


#include <iostream>
#include <thread>
#include <stop_token>

void foo(std::stop_token stoken) {
    // Função que será executada na thread, recebe um token para saber quando parar
    while (!stoken.stop_requested()) {  
        std::cout << "Running\n";
        std::this_thread::sleep_for(std::chrono::seconds(1));  // Espera 1 segundo
    }
}

int main() {
    std::jthread t(foo);  // Cria uma jthread que executa a função foo, passando automaticamente o stop_token

    std::this_thread::sleep_for(std::chrono::seconds(5)); 

    t.request_stop();  

    t.join();          // Aguarda a thread foo finalizar antes de continuar
    return 0;
}

Comparação Entre Linguagens

Recurso C++ Go Rust Elixir
Tarefas Leves Não (threads do SO) Sim (goroutines) Não (threads do SO) Sim (processos)
Segurança de Memória Manual GC + Manual Compile-time Runtime
Performance Máxima Alta Máxima Boa
Modelo de Concorrência Memória Compartilhada CSP (Canais) Ownership Modelo Actor