

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

# 를 사용한 비동기 프로그래밍 AWS SDK for C\$1\$1
<a name="async-methods"></a>

## 비동기식 SDK 메서드
<a name="asynchronous-sdk-methods"></a>

많은 메서드에 대해 SDK for C\$1\$1는 동기식 버전과 비동기식 버전을 모두 제공합니다. 이름에 `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` 메서드는 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` 메서드 내에서 `S3Client` 및 `PutObjectRequest` 객체를 생성하고 로컬 변수에 저장하는 대신, 이들 객체에 대한 참조를 허용합니다.

이 예시에서 `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;
}
```

[전체 예제](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/s3/put_object_async.cpp)는 Github에서 확인하세요.