Visual C++ の同時実行ランタイムを利用するアプリケーションがハングアップする問題について

こんにちは、Visual Studio サポート チームです。

今回は、Visual C++ で提供されている同時実行ランタイム (ConcRT : Concurrency Runtime) で確認されている問題と対処方法についてご案内します。この問題は Visual C++ 2010、2012、2013 で発生する可能性がありますが、Visual C++ 2015 以降では発生しません。

 

現象

ConcRT を使用するアプリケーションで、EnterCriticalSection 関数など、Win32 の同期オブジェクトを直接使用する処理を行うと、スレッド間でデッドロックが発生して、プログラムがハングアップする場合があります。

 

原因

Visual C++ 2013 以前の ConcRT では、Win32 の同期オブジェクトを直接利用しない形で内部の同期処理を実現していました。

この関係で、アプリケーション側のコードで Win32 の同期オブジェクトを直接使用すると、ConcRT 内の同期処理と アプリケーションで実装した同期処理の間でデッドロックが発生する場合があります。

 

対処方法

Visual C++ 2015 以降の ConcRT では同期処理の実装が見直され、Win32 の同期オブジェクトを直接的に利用する方法で統一されているため、この問題は発生しません。このため、可能であれば Visual C++ 2015 以降のバージョンへのバージョン アップをご検討ください。

バージョン アップを行うことが難しい場合は、Win32 の同期オブジェクトを直接利用する処理は控え、ConcRT が提供する critical_section クラスを利用するようアプリケーションを変更してください。

 

critical_section クラス
https://msdn.microsoft.com/ja-jp/library/dd492843(v=vs.100).aspx

 

以下に、critical_section クラスを RAII 形式で利用する例についてご案内します。

 

// RAII 用ロック クラス
class my_scoped_lock
{
private:
   Concurrency::critical_section * _cs;

public:

    my_scoped_lock(const Concurrency::critical_section& cs)
       : _cs(const_cast<Concurrency::critical_section * >(&cs))
   {
       _cs->lock();
   }
   ~my_scoped_lock()
   {
       _cs->unlock();
   }
};

// 使用例
class consumer_agent : public Concurrency::agent
{
protected:
   void run()
   {
       if (someCondition == true)
       {
           // このスコープの処理を排他制御します
           my_scoped_lock guard(_cs);
       }

       ...(略)...
   }
private:
   // critical_section オブジェクト
   Concurrency::critical_section _cs;
};

 

 

製品の問題でご不便をおかけしており誠に申し訳ございませんが、ConcRT を利用する際は上記内容をご参考いただけますと幸いです。