11

コード内のブースト依存関係の一部を取り除き、代わりに新しい C++11 機能 (Visual Studio 2013) を使用しようとしています。

boost::mutex一緒に使用したコンポーネントの 1 つで、boost::lock_guard<boost::mutex>すべてが正常に機能しました。std::mutex代わりにwithを使用するとstd::lock_guard<std::mutex>、 から戻るときに次のエラーが発生しますmain()

GrabberTester.exe の 0x7721E3BE (ntdll.dll) で未処理の例外: 0xC0000005: アクセス違反の読み取り場所 0xA6A6B491。

実際のプロジェクトは非常に複雑であるため、この問題を再現するために完全に機能するコード例を提供することは困難です。私の実際のプロジェクトでは、実行時にロードされる共有ライブラリでミューテックスが使用されます(ただし、から戻るまでにアンロードされているはずですmain())。

私の質問は次のとおりです。

  • と はまったく同じように動作するように設計されていますboost::mutexか?std::mutex
  • そうでない場合、違いは何ですか?std::mutexの代わりに使用する場合、何に注意する必要がありboost::mutexますか?
  • 共有ライブラリでは、boost::threadフレームワークでスレッドを作成しています。std::mutexは sでのみ使用でき、sstd::threadとは互換性がないboost::threadのでしょうか?

編集:

もう 1 つ気付きました。動的にロードされた共有ライブラリをアンロードすると、時間がかかります。(DLL はハードウェアにアクセスし、すべてを完全にシャットダウンするには時間がかかります)。ただし、に切り替えるとstd::mutex、DLL をすぐにアンロードできるように見えますが、から戻るとプログラムがクラッシュしmain()ます。std::mutex問題は特に DLL のコンテキストにあるという印象があります。

編集2:

アプリケーションと DLL の両方が、v120 ツールセットを使用してデバッグ構成で新たにビルドされ、ランタイム ライブラリ (/MTd) に静的にリンクされます。

編集3:

以下にコールスタックがあります。例外は、ドライバーのどこかから発生しているようです。偶然、私が使用しているミューテックスの実装に関係があることがわかりました。

ntdll.dll!7721e3be()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!7721e023()
kernel32.dll!76b014ad()
msvcr100.dll!71b0016a()
PS1080.dll!oniDriverDestroy() Line 29
OpenNI2.dll!oni::implementation::DeviceDriver::~DeviceDriver() Line 95
OpenNI2.dll!oni::implementation::Context::shutdown() Line 324
OpenNi2Grabber.dll!openni::OpenNI::shutdown() Line 2108
OpenNi2Grabber.dll!GrabberSingletonImpl::~GrabberSingletonImpl() Line 46
OpenNi2Grabber.dll!`GrabberSingletonImpl::getInstance'::`2'::`dynamic atexit destructor for 'inst''()
OpenNi2Grabber.dll!doexit(int code, int quick, int retcaller) Line 628
OpenNi2Grabber.dll!_cexit() Line 448
OpenNi2Grabber.dll!_CRT_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 169
OpenNi2Grabber.dll!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 399
OpenNi2Grabber.dll!_DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 340
ntdll.dll!7722b990()
ntdll.dll!77249bad()
ntdll.dll!77249a4f()
kernel32.dll!76b079ed()
GrabberTester.exe!__crtExitProcess(int status) Line 776
GrabberTester.exe!doexit(int code, int quick, int retcaller) Line 678
GrabberTester.exe!exit(int code) Line 417
GrabberTester.exe!__tmainCRTStartup() Line 264
GrabberTester.exe!mainCRTStartup() Line 165
kernel32.dll!76b0338a()
ntdll.dll!7722bf32()
ntdll.dll!7722bf05()

編集4:

おそらく、これは OpenNI2 SDK のバグであり、これらの非常に特定の条件下でのみ観察できます。そこで、この質問に openni タグを追加しました。しかし、それでも疑問が残ります: なぜそれは動作するのに動作しboost::mutexないのstd::mutexですか?

4

4 に答える 4

5

問題はおそらく静的な初期化地獄です。私は最近、ほぼ同じことを経験しました。何が起こっているかは次のとおりです。

  1. 静的ミューテックスがあります (静的なクラスのメンバーである可能性があります)。
  2. doexit() コードは、静的なもののクリーンアップを開始します。
  3. ミューテックスは doexit() のどこかで破棄されます
  4. ミューテックスが破棄された後、何かがミューテックスを使用します。多くの場合、デストラクターで使用されます。

問題は、静的オブジェクトの破棄順序がよくわからないことです。あなたが持っている場合:

static std::mutex staticMutex;

void someFunction()
{
    std::unique_lock<std::mutex> lock(staticMutex);
    doSomethingAwesome();
}

....

StaticObjA::~StaticObjA()
{
    someFunction();
}

次に、 ~StaticObjA() が呼び出されたときに、静的ミューテックスは既に削除/破棄/デッドビーフできます。オブジェクトが異なるコンパイル単位で定義されている (つまり、異なるファイルで定義されている) 場合、問題は悪化します。

解決するための私の推奨事項は、静的オブジェクトへの依存を減らすことです。イベントの順序を制御できるように、他のすべての構築/破棄を処理する 1 つの静的オブジェクトを使用することができます。または、静的をまったく使用しないでください。

于 2015-10-03T14:44:43.403 に答える
0

Mircosoft の std::mutex (または recursive_mutex など) を使用しないでください!!!! 私も同様の問題を抱えていました。私はVS2012を使用しています。

dll で std::mutex を使用する場合、この dll をアンロードしてはなりません。未定義の動作が発生するためです。(私の場合は 0xC0000005: アクセス違反の読み取り場所....)。または、dll をアンロードできません。( "?runtime?" はロード カウンターをインクリメントします。Double FreeLibrary() は dll をアンロードします )

于 2016-01-28T13:22:40.200 に答える
0

私は同じ問題を追加し、解決したのは...完全な手動クリーンアップ+再構築です! すべての .obj、.dll、.lib ファイルが削除されたことを確認します。

于 2015-02-16T15:44:00.640 に答える