インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス

デッドロック

インテル® Cilk™ Plus は古い機能 (非推奨) です。代わりに、OpenMP* またはインテル® TBB を使用してください。詳細は、「インテル® Cilk™ Plus の代わりに OpenMP* またはインテル® TBB を使用するためのアプリケーションの移行」を参照してください。

デッドロックは、2 つ以上のロックを使用していて、別々のストランドがロックを異なる順で取得した場合に発生します。2 つ以上のストランドが互いに取得しようとしている mutex を取得している場合、それらのストランドがデッドロックになる可能性があります。

以下に、2 つのストランドを使用した簡単な例を示します。この例では、1 つのリストから別のリストへリスト要素を移動します。各要素は、常にどちらかのリストにのみ存在することができます。L1L2 はリストで、sm1sm2 はそれぞれ L1L2 を保護する tbb::mutex オブジェクトです。

// コード例 A - L1 の先頭を L2 の最後に移動する
L2.
sm1.lock();
sm2.lock();
L2.push_back(*L1.begin);
L1.pop_front();
sm2.unlock();
sm1.unlock();
...
...
// コード例 B - L2 の先頭を L1 の最後に移動する
sm2.lock();
sm1.lock();
L1.push_back(*L2.begin);
L2.pop_front();
sm2.unlock();
sm1.unlock();

Fragment A を実行するストランドが sm1 のロックを取得し、Fragment A が sm2 のロックを取得する前に、Fragment B を実行する別のストランドが sm2 のロックを取得すると、デッドロックが発生します。どちらのストランドも処理を進めることができません。

一般的な解決方法は、両方のセグメントでロックを同じ順序で取得するようにすることです。例えば、Fragment B の 1 行目と 2 行目を入れ替えます。ロックは取得時と逆の順序で解放します。ただし、このようにしても、デッドロックが完全に回避できるわけではありません。