

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Programação assíncrona usando o AWS SDK para C\$1\$1
<a name="async-methods"></a>

## Métodos assíncronos do SDK
<a name="asynchronous-sdk-methods"></a>

Para muitos métodos, o SDK para C\$1\$1 fornece versões síncronas e assíncronas. Um método é assíncrono se inclui o sufixo `Async` em seu nome. Por exemplo, o método `PutObject` do Amazon S3 é síncrono, enquanto `PutObjectAsync` é assíncrono.

Como todas as operações assíncronas, um método do SDK assíncrono retorna antes que sua tarefa principal seja concluída. Por exemplo, o método `PutObjectAsync` retorna antes de concluir o upload do arquivo no bucket do Amazon S3. Enquanto a operação de upload continua, a aplicação pode realizar outras operações, inclusive chamar outros métodos assíncronos. A aplicação é notificada de que uma operação assíncrona foi concluída quando uma função de retorno de chamada associada é invocada.

As seções a seguir descrevem um exemplo de código que demonstra a chamada do método assíncrono `PutObjectAsync`. Cada seção se concentra em partes individuais de [todo o arquivo de origem](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/s3/put_object_async.cpp) do exemplo.

## Chamar métodos assíncronos do SDK
<a name="calling-sdk-asynchronous-methods"></a>

Em geral, a versão assíncrona de um método do SDK aceita os argumentos a seguir.
+ Uma referência ao mesmo objeto do tipo Solicitação que sua contraparte síncrona.
+ Uma referência a uma função de retorno de chamada do manipulador de respostas. Essa função de retorno de chamada é invocada quando a operação assíncrona é concluída. Um dos argumentos contém o resultado da operação.
+ Um `shared_ptr` opcional para um objeto `AsyncCallerContext`. O objeto é transmitido para o retorno de chamada do manipulador de respostas. Ele inclui uma propriedade UUID que pode ser usada para transmitir informações de texto para o retorno de chamada.

O método `uploadFileAsync` mostrado abaixo configura e chama o método `PutObjectAsync` do Amazon S3 do SDK para fazer upload de forma assíncrona de um arquivo para um bucket do Amazon S3.

A função recebe referências aos seguintes objetos: `S3Client` e `PutObjectRequest`. Ela as recebe da função principal porque precisamos garantir que esses objetos existam durante toda a duração das chamadas assíncronas.

A `shared_ptr` para um objeto `AsyncCallerContext` é alocada. Sua propriedade `UUID` é definida como o nome do objeto do Amazon S3. Para fins de demonstração, o retorno de chamada do manipulador de resposta acessa a propriedade e gera o respectivo valor.

A chamada para `PutObjectAsync` inclui um argumento de referência para a função de retorno de chamada do manipulador `uploadFileAsyncFinished` de respostas. Essa função de retorno de chamada é examinada em mais detalhes na próxima seção.

```
bool AwsDoc::S3::uploadFileAsync(const Aws::S3::S3Client &s3Client,
                                Aws::S3::Model::PutObjectRequest &request,
                                const Aws::String &bucketName,
                                const Aws::String &fileName) {
    request.SetBucket(bucketName);
    request.SetKey(fileName);

    const std::shared_ptr<Aws::IOStream> input_data =
            Aws::MakeShared<Aws::FStream>("SampleAllocationTag",
                                          fileName.c_str(),
                                          std::ios_base::in | std::ios_base::binary);

    if (!*input_data) {
        std::cerr << "Error: unable to open file " << fileName << std::endl;
        return false;
    }

    request.SetBody(input_data);

    // Create and configure the context for the asynchronous put object request.
    std::shared_ptr<Aws::Client::AsyncCallerContext> context =
            Aws::MakeShared<Aws::Client::AsyncCallerContext>("PutObjectAllocationTag");
    context->SetUUID(fileName);

    // Make the asynchronous put object call. Queue the request into a 
    // thread executor and call the uploadFileAsyncFinished function when the
    // operation has finished. 
    s3Client.PutObjectAsync(request, uploadFileAsyncFinished, context);

    return true;
}
```

Os recursos para uma operação assíncrona devem existir até que a operação seja concluída. Por exemplo, os objetos de cliente e de solicitação devem existir até que a aplicação receba a notificação de que a operação foi concluída. A aplicação em si não pode ser encerrada até que a operação assíncrona seja concluída.

Por esse motivo, o método `uploadFileAsync` aceita referências a objetos `S3Client` e `PutObjectRequest` em vez de criá-los no método `uploadFileAsync` e armazená-los em uma variável local. 

No exemplo, o método `PutObjectAsync` retorna para o chamador imediatamente após o início da operação assíncrona, permitindo que a cadeia de chamadas realize tarefas adicionais enquanto a operação de upload está em andamento. 

Se o cliente fosse armazenado em uma variável local no método `uploadFileAsync`, ele sairia do escopo quando o método retornasse. No entanto, o objeto de cliente deve continuar existindo até que a operação assíncrona seja concluída.

## Notificação da conclusão de uma operação assíncrona
<a name="notification-of-the-completion-of-an-asynchronous-operation"></a>

Quando uma operação assíncrona é concluída, uma função de retorno de chamada do manipulador de respostas da aplicação é invocada. Essa notificação inclui o resultado da operação. O resultado está contido na mesma classe do tipo Outcome retornada pela contraparte síncrona do método. No exemplo de código, o resultado está em um objeto `PutObjectOutcome`.

A função de retorno de chamada do manipulador de respostas do exemplo `uploadFileAsyncFinished` é mostrada abaixo. Ela confere se a operação assíncrona foi bem-sucedida ou falhou. Ela usa uma `std::condition_variable` para notificar o encadeamento da aplicação de que a operação assíncrona foi concluída.

```
// A mutex is a synchronization primitive that can be used to protect shared
// data from being simultaneously accessed by multiple threads.
std::mutex AwsDoc::S3::upload_mutex;

// A condition_variable is a synchronization primitive that can be used to
// block a thread, or to block multiple threads at the same time.
// The thread is blocked until another thread both modifies a shared
// variable (the condition) and notifies the condition_variable.
std::condition_variable AwsDoc::S3::upload_variable;
```

```
void uploadFileAsyncFinished(const Aws::S3::S3Client *s3Client,
                            const Aws::S3::Model::PutObjectRequest &request,
                            const Aws::S3::Model::PutObjectOutcome &outcome,
                            const std::shared_ptr<const Aws::Client::AsyncCallerContext> &context) {
    if (outcome.IsSuccess()) {
        std::cout << "Success: uploadFileAsyncFinished: Finished uploading '"
                  << context->GetUUID() << "'." << std::endl;
    } else {
        std::cerr << "Error: uploadFileAsyncFinished: " <<
                  outcome.GetError().GetMessage() << std::endl;
    }

    // Unblock the thread that is waiting for this function to complete.
    AwsDoc::S3::upload_variable.notify_one();
}
```

Com a operação assíncrona concluída, os recursos associados a ela podem ser liberados. Se desejar, você também poderá encerrar a aplicação.

O código a seguir demonstra como os métodos `uploadFileAsync` e `uploadFileAsyncFinished` são usados por uma aplicação.

A aplicação aloca os objetos `S3Client` e `PutObjectRequest` para que eles continuem existindo até que a operação assíncrona seja concluída. Após a chamada de `uploadFileAsync`, a aplicação pode realizar as operações que desejar. Para simplificar, o exemplo usa um `std::mutex` e uma `std::condition_variable` para esperar até que o retorno de chamada do manipulador de respostas o notifique de que a operação de upload foi concluída.

```
int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        std::cout << R"(
Usage:
    run_put_object_async <file_name> <bucket_name>
Where:
    file_name - The name of the file to upload.
    bucket_name - The name of the bucket to upload the object to.
)" << std::endl;
        return 1;
    }

    const Aws::SDKOptions options;
    Aws::InitAPI(options);
    {
        const Aws::String fileName = argv[1];
        const Aws::String bucketName = argv[2];

        // A unique_lock is a general-purpose mutex ownership wrapper allowing
        // deferred locking, time-constrained attempts at locking, recursive
        // locking, transfer of lock ownership, and use with
        // condition variables.
        std::unique_lock<std::mutex> lock(AwsDoc::S3::upload_mutex);

        // Create and configure the Amazon S3 client.
        // This client must be declared here, as this client must exist
        // until the put object operation finishes.
        const Aws::S3::S3ClientConfiguration config;
        // Optional: Set to the AWS Region in which the bucket was created (overrides config file).
        // config.region = "us-east-1";

        const Aws::S3::S3Client s3Client(config);

        // Create the request object.
        // This request object must be declared here, because the object must exist
        // until the put object operation finishes.
        Aws::S3::Model::PutObjectRequest request;

        AwsDoc::S3::uploadFileAsync(s3Client, request, bucketName, fileName);

        std::cout << "main: Waiting for file upload attempt..." <<
                  std::endl << std::endl;

        // While the put object operation attempt is in progress,
        // you can perform other tasks.
        // This example simply blocks until the put object operation
        // attempt finishes.
        AwsDoc::S3::upload_variable.wait(lock);

        std::cout << std::endl << "main: File upload attempt completed."
                  << std::endl;
    }
    Aws::ShutdownAPI(options);

    return 0;
}
```

Veja o exemplo completo no [GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/s3/put_object_async.cpp).