C++
AWS
S3
AWS-SDK-for-C++

AWS SDK for C++をマルチスレッドで利用する際の注意点

AWS SDK for C++をマルチスレッドで利用する場合、Aws::InitAPIAws::ShutdownAPI の呼び出しタイミングでハマったのでメモ。


環境準備

DockerとMinioを利用して開発環境を用意しています。

下記記事の設定や実装をベースにしています。

DockerとMinioでAWS SDK for C++の開発環境を構築する - Qiita

https://qiita.com/kai_kou/items/d160948553504848d380


検証


シングルスレッドで実行

シングルスレッドで実行してみます。main.cppmain メソッドを以下のように変更します。


main.cpp

()

int main()
{
// シングルスレッドで実行
put_object("hoge1.txt");
put_object("hoge2.txt");

return 0;
}



コンテナ内

# cd /cpp-dev/build

# cmake ..
# cmake --build .
# ./main
hoge1.txt Done!
hoge2.txt Done!

問題なく実行できました。

Minioが利用するディレクトリにファイルが保存されたのも確認できます。

> tree data/hoge

data/hoge/
├── hoge1.txt
└── hoge2.txt
> cat data/hoge/hoge1.txt
hoge!


マルチスレッドで実行

main.cppmain メソッドでマルチスレッド実行するように変更して実行してみます。


main.cpp

()

int main()
{
// マルチスレッドで実行
std::thread th_1(put_object, "hoge3.txt");
std::thread th_2(put_object, "hoge4.txt");
th_1.join();
th_2.join();

return 0;
}



コンテナ内

# cmake --build .

# ./main
hoge3.txt Done!
main: /aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/MonitoringManager.cpp:55:
void Aws::Monitoring::OnRequestSucceeded(
const String&, const String&,
const std::shared_ptr<const Aws::Http::HttpRequest>&,
const HttpResponseOutcome&,
const Aws::Monitoring::CoreMetricsCollection&,
Aws::Vector<void*>&
): Assertion `s_monitors' failed.
Aborted

1つめは実行されて、2つめがエラーになりました。

Assertions_monitors' failed.あたりで調べてみると、Aws::InitAPIAws::ShutdownAPI` の実行タイミングに問題がありそうでした。

How to handle Aws::ShutdownAPI with multiple threads on Windows? · Issue #1050 · aws/aws-sdk-cpp

https://github.com/aws/aws-sdk-cpp/issues/1050

c++ - Why does an assert(s_monitors) in MonitoringManager::OnRequestSucceeded() fail? - Stack Overflow

https://stackoverflow.com/questions/54290073/why-does-an-asserts-monitors-in-monitoringmanageronrequestsucceeded-fail

InitAPIPutObjectShutdownAPI の実行後にログを仕込んてみるとPutObject 実行時に落ちてるみたいです。マルチスレッドなので、hoge3.txthoge4.txt の実行タイミングが入れ替わることもあります。

# ./main

hoge3.txt InitAPI
hoge4.txt InitAPI
hoge3.txt PutObject
hoge3.txt Done!
hoge3.txt ShutdownAPI
main: /aws-sdk-cpp/aws-cpp-sdk-core/source/monitoring/MonitoringManager.cpp:55:
void Aws::Monitoring::OnRequestSucceeded(
const String&, const String&,
const std::shared_ptr<const Aws::Http::HttpRequest>&,
const HttpResponseOutcome&,
const Aws::Monitoring::CoreMetricsCollection&,
Aws::Vector<void*>&
): Assertion `s_monitors' failed.
Aborted


原因と解決策

おそらくですが、Aws::InitAPIAws::ShutdownAPI がグローバルな初期化関数とクリーンアップ機能なので、マルチスレッドスレッド中に呼び出すとダメっぽいです。

なので、put_object メソッド内で呼び出しているAws::InitAPIAws::ShutdownAPImain メソッドに移動してやればひとまず解決です。


main.cpp

()

// put_objectメソッド内のInitAPIとShutdownAPI呼び出しをなくす

int main()
{
Aws::SDKOptions options;
Aws::InitAPI(options);

// マルチスレッドで実行
std::thread th_1(put_object, "hoge3.txt");
std::thread th_2(put_object, "hoge4.txt");
th_1.join();
th_2.join();

Aws::ShutdownAPI(options);

return 0;
}


Aws::ShutdownAPI についてはAWS公式のGitHubリポジトリにあるサンプルだと複数回実行しても問題なさそうな実装になっているのですが、シングルスレッドで実行するので問題が発生しないのだと思います。

マルチスレッドで実行する場合はAws::InitAPI と同様にメインスレッドで呼び出すのが無難みたいです。

aws-doc-sdk-examples/s3-demo.cpp at master · awsdocs/aws-doc-sdk-examples

https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/cpp/example_code/s3/s3-demo.cpp


参考

How to handle Aws::ShutdownAPI with multiple threads on Windows? · Issue #1050 · aws/aws-sdk-cpp

https://github.com/aws/aws-sdk-cpp/issues/1050

c++ - Why does an assert(s_monitors) in MonitoringManager::OnRequestSucceeded() fail? - Stack Overflow

https://stackoverflow.com/questions/54290073/why-does-an-asserts-monitors-in-monitoringmanageronrequestsucceeded-fail

aws-doc-sdk-examples/s3-demo.cpp at master · awsdocs/aws-doc-sdk-examples

https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/cpp/example_code/s3/s3-demo.cpp

DockerとMinioでAWS SDK for C++の開発環境を構築する - Qiita

https://qiita.com/kai_kou/items/d160948553504848d380

C/C++によるマルチスレッドプログラミング入門 - Qiita

https://qiita.com/nsnonsugar/items/be8a066c6627ab5b052a