Programação assíncrona usando o AWS SDK para C++ - AWS SDK para C++

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++

Métodos assíncronos do SDK

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

Como todas as operações assíncronas, um método SDK assíncrono retorna antes que sua tarefa principal seja concluída. Por exemplo, o PutObjectAsync método retorna antes de concluir o upload do arquivo para o bucket do Amazon S3. Enquanto a operação de upload continua, o aplicativo pode realizar outras operações, inclusive chamar outros métodos assíncronos. O aplicativo é notificado 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 PutObjectAsync assíncrono. Cada seção se concentra em partes individuais de todo o arquivo de origem do exemplo.

Chamando métodos assíncronos do SDK

Em geral, a versão assíncrona de um método SDK aceita os seguintes argumentos.

  • 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 opcional shared_ptr para um AsyncCallerContext objeto. O objeto é passado para o retorno de chamada do manipulador de resposta. Ele inclui uma propriedade UUID que pode ser usada para passar informações de texto para o retorno de chamada.

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

A função recebe referências a um S3Client objeto e a um PutObjectRequest objeto. Ele os 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 AsyncCallerContext objeto é alocado. Sua UUID propriedade é definida como o nome do objeto Amazon S3. Para fins de demonstração, o retorno de chamada do manipulador de resposta acessa a propriedade e gera seu valor.

A chamada para PutObjectAsync inclui um argumento de referência para a função de retorno de chamada do manipulador de respostas. uploadFileAsyncFinished Essa função de retorno de chamada é examinada com 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, o cliente e os objetos de solicitação devem existir até que o aplicativo receba a notificação de que a operação foi concluída. O aplicativo em si não pode ser encerrado até que a operação assíncrona seja concluída.

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

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

Se o cliente fosse armazenado em uma variável local no uploadFileAsync método, ele sairia do escopo quando o método retornasse. No entanto, o objeto 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

Quando uma operação assíncrona é concluída, uma função de retorno de chamada do manipulador de respostas do aplicativo é 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 PutObjectOutcome objeto.

A função de retorno de chamada do manipulador de resposta do exemplo uploadFileAsyncFinished é mostrada abaixo. Ele verifica se a operação assíncrona foi bem-sucedida ou falhou. Ele usa std::condition_variable a para notificar o encadeamento do aplicativo 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. O aplicativo também pode ser encerrado, se desejar.

O código a seguir demonstra como os uploadFileAsyncFinished métodos uploadFileAsync e são usados por um aplicativo.

O aplicativo aloca os PutObjectRequest objetos S3Client e para que eles continuem existindo até que a operação assíncrona seja concluída. Após a chamadauploadFileAsync, o aplicativo pode realizar as operações que desejar. Para simplificar, o exemplo usa um std::mutex e std::condition_variable para esperar até que o retorno de chamada do manipulador de resposta 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.