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

環境準備

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

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

DockerとMinioでAWS SDK for C++の開発環境を構築する – Qiita
https://cloudpack.media/46547

検証

シングルスレッドで実行

シングルスレッドで実行してみます。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://cloudpack.media/46547

C/C++によるマルチスレッドプログラミング入門 – Qiita
https://qiita.com/nsnonsugar/items/be8a066c6627ab5b052a

元記事はこちら

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