使用 進行非同步程式設計 適用於 C++ 的 AWS SDK - 適用於 C++ 的 AWS SDK

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

使用 進行非同步程式設計 適用於 C++ 的 AWS SDK

非同步 SDK 方法

對於許多方法,適用於 C++ 的 SDK 同時提供同步和非同步版本。如果方法在名稱中包含Async尾碼,則表示方法為非同步。例如,Amazon S3 方法PutObject是同步的,而 PutObjectAsync是非同步的。

如同所有非同步操作,非同步 SDK 方法會在其主要任務完成之前傳回 。例如, PutObjectAsync方法會在完成將檔案上傳至 Amazon S3 儲存貯體之前傳回 。當上傳操作繼續時,應用程式可以執行其他操作,包括呼叫其他非同步方法。叫用相關聯的回呼函數時,應用程式會收到非同步操作已完成的通知。

下列各節說明程式碼範例,示範呼叫PutObjectAsync非同步方法。每個區段著重於範例整個來源檔案中的個別部分。

呼叫 SDK 非同步方法

一般而言, SDK 方法的非同步版本接受下列引數。

  • 與同步對等物件相同的請求類型物件的參考。

  • 回應處理常式回呼函數的參考。當非同步操作完成時,會叫用此回呼函數。其中一個引數包含操作的結果。

  • AsyncCallerContext 物件shared_ptr的選用 。物件會傳遞至回應處理常式回呼。它包含 UUID 屬性,可用於將文字資訊傳遞至回呼。

以下顯示uploadFileAsync的方法會設定並呼叫 SDK 的 Amazon S3 PutObjectAsync方法,以非同步方式將檔案上傳至 Amazon S3 儲存貯體。

函數會收到 S3Client 物件和 PutObjectRequest 物件的參考。它從主要函數接收它們,因為我們需要確保這些物件在整個非同步呼叫期間都存在。

物件shared_ptrAsyncCallerContext已配置。其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方法接受 S3ClientPutObjectRequest 物件的參考,而不是在 uploadFileAsync方法中建立它們,並將它們儲存在本機變數中。

在此範例中, 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 上的完整範例