Multithreading com std::packaged_task em C++

O std::packaged_task é uma classe template da biblioteca padrão C++ que encapsula um objeto chamável, permitindo a obtenção assíncrona do resultado de sua execução. Internamente, ele gerencia doiss componentes principais: a tarefa encapsulada e um estado compartilhado.

A tarefa encapsulada refere-se ao objeto chamável, como um ponteiro para função, um functor ou uma expressão lambda. O estado compartilhado armazena o valor de retorno da tarefa ou qualquer exceção lançada durante sua execução, sendo acessível através de um objeto std::future.

O ciclo de vida do estado compartilhado persiste até que todos os objetos associados sejam destruídos. A seguir, um exemplo demonstrando seu uso básico, com uma função alternativa para cálculo de fatorial:


#include <iostream>
#include <future>
#include <thread>

int fatorial(int n) {
    if (n <= 1) return 1;
    int resultado = 1;
    for (int i = 2; i <= n; ++i) {
        resultado *= i;
    }
    return resultado;
}

int main() {
    std::packaged_task<int(int)> tarefa(fatorial);
    std::future<int> futuro = tarefa.get_future();

    std::thread thread_exec(std::move(tarefa), 7);

    int valor = futuro.get();
    std::cout << "Fatorial de 7 é: " << valor << std::endl;

    thread_exec.join();
    return 0;
}

Construtores

  • Construtor padrão: packaged_task() noexcept;
    Inicializa um objeto sem estado compartilhado válido.
  • Construtor por inicialização: template<class Fn> explicit packaged_task(Fn&& fn);
    Cria um packaged_task com a tarefa fornecida.
  • Construtor com alocador: template<class Fn, class Alloc> explicit packaged_task(allocator_arg_t, const Alloc& a, Fn&& fn);
    Permite especificar um alocador personalizado para o estado compartilhado.

O construtor de cópia é desabilitado:


packaged_task(const packaged_task&) = delete;

O construtor de movimento é permitido:


packaged_task(packaged_task&& outro) noexcept;

Funções Membro

  • std::future<R> get_future();
    Retorna um objeto std::future vinculado ao estado compartilhado.

  • bool valid() const noexcept;
    Verifica se o packaged_task possui um estado compartilhado válido. Objetos criados pelo construtor padrão retornam false, a menos que tenham sido movidos ou torcados. ```

    std::future executar(std::packaged_task<int(int)&> tsk, int arg) { if (tsk.valid()) { auto f = tsk.get_future(); std::thread(std::move(tsk), arg).detach(); return f; } return {}; }

  • template<class... Args> void operator()(Args&&... args);
    Invoca a tarefa encapsulada com os argumentos fornecidos. Se a execução for bem-suceidda, o valor de retorno é armazenado no estado compartilhado; caso contrário, a exceção é capturada. Em ambos os casos, o estado fica pronto para consulta via std::future.

  • template<class... Args> void make_ready_at_thread_exit(Args&&... args);
    Executa a tarefa, mas marca o estado como pronto somente quando a thread corrente termina. Isso é útil para sincronização fina com o término da thread.

  • void reset();
    Recria o estado compartilhado, mantendo a tarefa original. Permite reutilizar o mesmo packaged_task para múltiplas execuções. ```

    #include #include #include

    int dobro(int x) { return x * 2; }

    int main() { std::packaged_task<int(int)> tarefa(dobro); auto futuro = tarefa.get_future();

      std::thread(std::move(tarefa), 50).detach();
      std::cout << "Dobro de 50: " << futuro.get() << std::endl;
    
      tarefa.reset();
      futuro = tarefa.get_future();
      std::thread(std::move(tarefa), 75).detach();
      std::cout << "Dobro de 75: " << futuro.get() << std::endl;
    
      return 0;
    

    }

  • void swap(packaged_task& outro) noexcept;
    Troca o conteúdo (incluindo o estado compartilhado e a tarefa) com outro objeto packaged_task.

Tags: C++ std::packaged_task Multithreading std::future programação concorrente

Publicado em 6-20 04:45