AWS SDK for C++를 사용한 비동기 프로그래밍 - AWS SDK for C++

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

AWS SDK for C++를 사용한 비동기 프로그래밍

비동기식 SDK 메서드

많은 메서드에 대해 SDK for C++는 동기식 버전과 비동기식 버전을 모두 제공합니다. 이름에 Async 접미사가 포함된 메서드는 비동기식입니다. 예를 들어 Amazon S3 메서드 PutObject는 동기식이고 PutObjectAsync는 비동기식입니다.

모든 비동기 작업과 마찬가지로, 비동기 SDK 메서드는 기본 태스크가 완료되기 전에 반환됩니다. 예를 들어 PutObjectAsync 메서드는 파일을 Amazon S3 버킷에 업로드하는 작업을 완료하기 전에 반환됩니다. 업로드 작업이 계속되는 동안 애플리케이션은 다른 비동기 메서드 호출을 포함하여 다른 작업을 수행할 수 있습니다. 연결된 콜백 함수가 호출될 때 비동기 작업이 완료되었다는 알림이 애플리케이션에 전송됩니다.

다음 섹션에서는 PutObjectAsync 비동기식 메서드 호출을 보여주는 코드 예제를 설명합니다. 각 섹션은 예제의 전체 소스 파일에서 개별 부분을 집중적으로 다룹니다.

SDK 비동기식 메서드 호출

일반적으로 SDK 메서드의 비동기 버전은 다음 인수를 허용합니다.

  • 동기식 버전과 동일한 요청 유형 객체에 대한 참조.

  • 응답 핸들러 콜백 함수에 대한 참조. 이 콜백 함수는 비동기 작업이 완료되면 호출됩니다. 인수 중 하나에는 작업의 결과가 포함됩니다.

  • AsyncCallerContext 객체에 대한 shared_ptr(선택 사항). 이 객체는 응답 핸들러 콜백에 전달됩니다. 여기에는 텍스트 정보를 콜백에 전달하는 데 사용할 수 있는 UUID 속성이 포함됩니다.

아래에 표시된 uploadFileAsync 메서드는 Amazon S3 버킷에 파일을 비동기적으로 업로드하는 SDK의 Amazon S3 PutObjectAsync 메서드를 설정하고 호출합니다.

함수는 S3Client 객체 및 PutObjectRequest 객체에 대한 참조를 수신합니다. 함수가 이러한 참조를 메인 함수로부터 수신하는 이유는 비동기 호출이 지속되는 전체 기간 동안 이 객체들이 존재하도록 보장해야 하기 때문입니다.

AsyncCallerContext 객체에 대한 shared_ptr이 할당됩니다. 해당 객체의 UUID 속성은 Amazon S3 객체 이름으로 설정됩니다. 시연을 위해 응답 핸들러 콜백은 속성에 액세스하여 해당 값을 출력합니다.

PutObjectAsync 호출에는 응답 핸들러 콜백 함수 uploadFileAsyncFinished에 대한 참조 인수가 포함됩니다. 이 콜백 함수는 다음 섹션에서 자세히 살펴봅니다.

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; }

비동기 작업의 리소스는 작업이 완료될 때까지 존재해야 합니다. 예를 들어, 클라이언트 및 요청 객체는 애플리케이션에서 작업 완료 알림을 수신할 때까지 존재해야 합니다. 애플리케이션 자체는 비동기 작업이 완료되기 전까지 종료될 수 없습니다.

이러한 이유로 uploadFileAsync 메서드는 uploadFileAsync 메서드 내에서 S3ClientPutObjectRequest 객체를 생성하고 로컬 변수에 저장하는 대신, 이들 객체에 대한 참조를 허용합니다.

이 예시에서 PutObjectAsync 메서드는 비동기 작업을 시작한 직후 호출자에게 반환되므로, 업로드 작업이 진행되는 동안 호출 체인이 추가 작업을 수행할 수 있습니다.

클라이언트가 uploadFileAsync 메서드의 로컬 변수에 저장된 경우 메서드가 반환될 때 범위를 벗어나게 됩니다. 그러나 클라이언트 객체는 비동기 작업이 완료될 때까지 계속 존재해야 합니다.

비동기 작업 완료 알림

비동기 작업이 완료되면 애플리케이션 응답 핸들러 콜백 함수가 호출됩니다. 이 알림에는 작업 결과가 포함됩니다. 결과는 메서드의 동기식 대응 메서드에서 반환하는 것과 동일한 결과 유형 클래스에 포함됩니다. 코드 예제에서 결과는 PutObjectOutcome 객체에 있습니다.

예제의 응답 핸들러 콜백 함수 uploadFileAsyncFinished는 다음과 같습니다. 비동기 작업이 성공 또는 실패했는지 확인합니다. std::condition_variable을을 사용하여 애플리케이션 스레드에 비동기 작업이 완료되었음을 알립니다.

// 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(); }

비동기 작업이 완료되면 이와 관련된 리소스를 해제할 수 있습니다. 원하는 경우 애플리케이션을 종료할 수도 있습니다.

다음 코드는 애플리케이션에서 uploadFileAsyncuploadFileAsyncFinished 메서드를 사용하는 방법을 보여줍니다.

애플리케이션에서는 비동기 작업이 완료될 때까지 S3ClientPutObjectRequest 객체가 계속 존재하도록 해당 객체를 할당합니다. uploadFileAsync 호출 후 애플리케이션은 원하는 작업을 수행할 수 있습니다. 단순화를 위해 이 예제에서는 std::mutexstd::condition_variable을 사용하여 응답 핸들러 콜백으로 업로드 작업 완료 알림이 전달될 때까지 대기합니다.

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; }

전체 예제는 Github에서 확인하세요.