

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# を使用した非同期プログラミング AWS SDK for C\$1\$1
<a name="async-methods"></a>

## 非同期 SDK メソッド
<a name="asynchronous-sdk-methods"></a>

多くのメソッドに対して、AWS SDK for C\$1\$1 では同期版と非同期版の両方が用意されています。メソッド名に `Async` サフィックスが付いている場合、そのメソッドは非同期です。例えば、Amazon S3 メソッド `PutObject` は同期ですが、`PutObjectAsync` は非同期です。

すべての非同期オペレーションと同様に、非同期 SDK メソッドは main の処理が終了する前に制御を返します。例えば、`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 メソッドの非同期バージョンは次の引数を受け入れます。
+ 同期版のメソッドで使用されるものと同じ型のリクエストオブジェクトへの参照。
+ レスポンスハンドラーコールバック関数への参照。このコールバック関数は、非同期オペレーションが終了すると呼び出されます。引数の 1 つには、オペレーションの結果が含まれます。
+ `AsyncCallerContext` オブジェクトへのオプションの `shared_ptr`。このオブジェクトはレスポンスハンドラーコールバック関数に渡されます。テキスト情報をコールバックに渡すために使用できる UUID プロパティが含まれています。

次に示す `uploadFileAsync` メソッドは、SDK の Amazon S3 `PutObjectAsync` メソッドを設定して呼び出し、ファイルを Amazon S3 バケットに非同期的にアップロードします。

この関数は `S3Client` オブジェクトと `PutObjectRequest` オブジェクトへの参照を受け取ります。これらのオブジェクトは、非同期呼び出しが完了するまで存在している必要があるため、main 関数から渡されます。

`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` メソッドは `S3Client` および `PutObjectRequest` オブジェクトを `uploadFileAsync` メソッド内部で作成してローカル変数に保存するのではなく、それらのオブジェクトへの参照を引数として受け取ります。

この例では、`PutObjectAsync` メソッドは非同期処理を開始した直後に呼び出し元へ制御を返すため、呼び出し元ではアップロード処理中に他のタスクを実行できます。

`uploadFileAsync` メソッド内でクライアントがローカル変数に保存されていた場合、メソッド終了時にスコープ外となります。しかし、クライアントオブジェクトは非同期処理が完了するまで存在し続ける必要があります。

## 非同期オペレーションの完了通知
<a name="notification-of-the-completion-of-an-asynchronous-operation"></a>

非同期オペレーションが完了すると、アプリケーションのレスポンスハンドラーコールバック関数が呼び出されます。この通知には、オペレーションの結果が含まれます。結果は、同期版メソッドが返すものと同じ Outcome 型クラスに保存されます。このコード例では、結果は `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) で完全な例をご覧ください。