

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

# 使用 進行非同步程式設計 適用於 C\$1\$1 的 AWS SDK
<a name="async-methods"></a>

## 非同步 SDK 方法
<a name="asynchronous-sdk-methods"></a>

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

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

下列各節說明程式碼範例，示範呼叫`PutObjectAsync`非同步方法。每個區段著重於範例[整個來源檔案中](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/s3/put_object_async.cpp)的個別部分。

## 呼叫 SDK 非同步方法
<a name="calling-sdk-asynchronous-methods"></a>

一般而言， SDK 方法的非同步版本接受下列引數。
+ 與同步對等物件相同的請求類型物件的參考。
+ 回應處理常式回呼函數的參考。當非同步操作完成時，會叫用此回呼函數。其中一個引數包含操作的結果。
+ `AsyncCallerContext` 物件`shared_ptr`的選用項目。物件會傳遞至回應處理常式回呼。它包含 UUID 屬性，可用於將文字資訊傳遞至回呼。

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

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

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

在此範例中， `PutObjectAsync`方法會在開始非同步操作後立即傳回給發起人，讓呼叫鏈能夠在上傳操作進行時執行其他任務。

如果用戶端存放在 `uploadFileAsync`方法的本機變數中，則會在傳回方法時超出範圍。不過，用戶端物件必須繼續存在，直到非同步操作完成為止。

## 非同步操作完成通知
<a name="notification-of-the-completion-of-an-asynchronous-operation"></a>

當非同步操作完成時，會叫用應用程式回應處理常式回呼函數。此通知包含 操作的結果。結果會包含在方法同步對等項目傳回的相同結果類型類別中。在程式碼範例中，結果位於 `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();
}
```

完成非同步操作後，即可釋出與其相關聯的資源。如有需要，應用程式也可以終止。

下列程式碼示範應用程式如何使用 `uploadFileAsync`和 `uploadFileAsyncFinished`方法。

應用程式會配置 `S3Client`和 `PutObjectRequest` 物件，使其持續存在，直到非同步操作完成為止。呼叫 後`uploadFileAsync`，應用程式可以執行所需的任何操作。為了簡化，範例使用 `std::mutex`和 `std::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 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/s3/put_object_async.cpp)。