メインコンテンツ

ダブル ロック

ロック関数はタスク中 2 回呼び出されますが、その間にロック解除関数の呼び出しはありません。

説明

このチェッカーは、既定の Polyspace™ as You Code 解析では非アクティブにされますPolyspace as You Code 解析で非アクティブにされるチェッカー (Polyspace Access)を参照してください

この欠陥は、以下の場合に発生します。

  • タスクはロック関数 my_lock を呼び出します。

  • タスクが対応するロック解除関数を呼び出す前に my_lock を再度呼び出します。

マルチタスキング コードでは、ロック関数はコードのクリティカル セクションを開始し、ロック解除関数はそれを終了させます。タスク task1 がロック関数 lock を呼び出すとき、lock を呼び出し中の他のタスクは task が対応するロック解除関数を呼び出すまで待たなくてはなりません。

この欠陥を検出するには、次のいずれかのメソッドを使用してロック関数とロック解除関数を指定します。

リスク

ロック関数を呼び出すと、クリティカル セクションが開始されるため、他のタスクは同じクリティカル セクションに入るまで待機する必要があります。同じロック関数がクリティカル セクション内から再度呼び出された場合、そのタスク自体がブロックされます。

修正方法

修正方法は欠陥の根本原因によって異なります。ダブル ロックの欠陥は多くの場合、コーディング エラーを示します。前のクリティカル セクションを終了するためのロック解除関数を呼び出さずに、次のクリティカル セクションを開始した可能性があります。2 番目のクリティカル セクション用に別のロック関数を使用する必要があった可能性もあります。

コードの各クリティカル セクション、つまり、Atomic ブロックとして実行するセクションを特定します。セクションの最初でロック関数を呼び出します。クリティカル セクション内で、ロック関数を再度呼び出していないことを確認します。セクションの最後で、そのロック関数に対応するロック解除関数を呼び出します。

以下の修正例を参照してください。この問題を回避するには、同じモジュール内のロック関数とロック解除関数を同じ抽象化レベルで呼び出す手法に従うことをお勧めします。次の例の場合、func はロック関数とロック解除関数を同じレベルで呼び出していますが、func2 はそうではありません。

void func() {
  my_lock();
  {
    ...
  }
  my_unlock();
}

void func2() {
  {
   my_lock();
   ...
  }
  my_unlock();
}

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

チェッカーの拡張

Polyspace でサポートされていないロック関数を使用する場合があります。その場合、ロック関数を、POSIX® の既知の同等の関数にマッピングすることで、このチェッカーを拡張します。サポートされていないマルチスレッド環境への同時実行欠陥チェッカーの拡張を参照してください。

すべて展開する



int global_var;

void lock(void);
void unlock(void);

void task1(void)
{
    lock();
    global_var += 1;
    lock(); 
    global_var += 1;
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}

この例では、マルチタスクの動作をエミュレートするため、以下のオプションを指定しなければなりません。

コマンド ラインでは以下を使用できます。

 polyspace-bug-finder
   -entry-points task1,task2
   -critical-section-begin lock:cs1
   -critical-section-end unlock:cs1

task1lock(); の呼び出しでクリティカル セクションを開始します。task1unlock(); を呼び出してクリティカル セクションを離れる前に lock を再度呼び出します。

修正 — 最初のロックを削除

最初の global_var+=1; をクリティカル セクションの外部に置きたい場合、1 つの修正として lock の最初の呼び出しを削除できます。ただし、他のタスクが global_var を使用している場合、このコードはデータ レースエラーを発生させることがあります。



int global_var;

void lock(void);
void unlock(void);

void task1(void)
{
    global_var += 1;
    lock(); 
    global_var += 1;
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}
修正— — 2番目のロックを削除

最初の global_var+=1; をクリティカル セクションの内部に置きたい場合、1 つの修正方法として lock の最初の呼び出しを削除できます。



int global_var;

void lock(void);
void unlock(void);

void task1(void)
{
    lock();
    global_var += 1;
    global_var += 1;
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}
修正 — 別のロック解除を追加

2番目の global_var+=1; をクリティカル セクションの内部に置きたい場合、他の修正方法として unlock の呼び出しを別に追加することができます。



int global_var;

void lock(void);
void unlock(void);

void task1(void)
{
    lock();
    global_var += 1;
    unlock();
    lock();
    global_var += 1;
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}


int global_var;

void lock(void);
void unlock(void);

void performOperation(void) {
  lock();
  global_var++;
}

void task1(void)
{
    lock();
    global_var += 1;
    performOperation();
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}

この例では、マルチタスクの動作をエミュレートするため、以下のオプションを指定しなければなりません。

コマンド ラインでは以下を使用できます。

 polyspace-bug-finder
   -entry-points task1,task2
   -critical-section-begin lock:cs1
   -critical-section-end unlock:cs1

task1 はクリティカル セクションを lock(); の呼び出しで開始します。task1 は関数 performOperation を呼び出します。performOperationでは、task1 はまだ unlock(); を呼び出してクリティカル セクションを離れる前にもかかわらず、lock が再度呼び出されます。

欠陥についての結果の詳細には、欠陥の原因となった命令の順序が表示されます。たとえば、クリティカル セクションの最初のエントリに続いて、次の実行パスが表示されます。

  • 関数 performOperation に入る。

  • performOperation 内部で、再度同じクリティカル セクションに入ろうと試みる。

各イベントをクリックすると、ソース コード内の対応する行に移動できます。

修正— — 2番目のロックを削除

1 つの修正方法として、task1 内の lock の呼び出しを削除します。



int global_var;

void lock(void);
void unlock(void);

void performOperation(void) {
  global_var++;
}

void task1(void)
{
    lock();
    global_var += 1;
    performOperation();
    unlock();
}

void task2(void)
{
    lock(); 
    global_var += 1;
    unlock();
}

結果情報

グループ: 同時実行
言語: C | C++
既定値: オン
コマンド ライン構文: DOUBLE_LOCK
影響度: High

バージョン履歴

R2014b で導入

すべて展開する