Double lock

Функция блокировки вызывается дважды в задаче без промежуточного вызова для разблокировки функции

Описание

Этот дефект возникает, когда:

  • Задача вызывает функцию блокировки my_lock.

  • Задача вызывает my_lock снова перед вызовом соответствующей функции разблокировки.

В многозадачном коде функция блокировки начинает критический раздел кода и функция разблокировки прекращает его. Когда задача task1 вызывает функцию блокировки lock, другие задачи, вызывающие lock необходимо подождать до task вызывает соответствующую функцию разблокировки. Polyspace® требует, чтобы функции блокировки и разблокировки имели форму void func(void).

Чтобы найти этот дефект, перед анализом необходимо задать опции многозадачности. Чтобы задать эти опции, на панели Configuration выберите Multitasking.

Риск

Вызов функции блокировки начинает критический раздел, так что другие задачи должны ждать, чтобы войти в тот же критический раздел. Если та же функция блокировки вызывается снова в критическом разделе, задача блокируется сама.

Зафиксировать

Исправление зависит от первопричины дефекта. Дефект двойной блокировки часто указывает на ошибку кодирования. Возможно, вы пропустили вызов функции разблокировки, чтобы закончить предыдущий критический раздел и начали следующий критический раздел. Возможно, вы хотели использовать другую функцию блокировки для второго критического раздела.

Идентифицируйте каждый критический раздел кода, то есть раздел, который вы хотите выполнить как атомарный блок. Вызовите функцию блокировки в начале раздела. В критическом разделе убедитесь, что вы не вызываете функцию блокировки снова. В конце раздела вызовите функцию разблокировки, которая соответствует функции блокировки.

См. примеры исправлений ниже. Чтобы избежать проблемы, можно следовать практике вызова функций блокировки и разблокировки в том же модуле на том же уровне абстракции. Например, в этом примере func вызывает функцию блокировки и разблокировки на том же уровне, но func2 не делает.

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

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

Если вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другой проверки. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.

Примеры

расширить все



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

task1 входит в критический раздел через вызов lock();. task1 вызывает lock снова, прежде чем он покинет критический раздел через вызов unlock();.

Коррекция - Снимите первый замок

Если вам нужен первый global_var+=1; чтобы находиться вне критической секции, одной из возможных коррекций является удаление первого вызова на lock. Однако, если используются другие задачи global_var, этот код может создать Data race ошибка.



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();
}
Коррекция - Снимите второй замок

Если вам нужен первый global_var+=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();
}
Коррекция - Добавить другую разблокировку

Если вам нужен второй 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();
}

В этом примере, чтобы эмулировать поведение в многозадачном режиме, вы должны задать следующие опции:

ОпцияСпецификация
Configure multitasking manually
Tasks (-entry-points)

task1

task2

Critical section details (-critical-section-begin -critical-section-end)Starting routineEnding routine
lockunlock

В командной строке можно использовать следующее:

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

task1 входит в критический раздел через вызов lock();. task1 вызывает функцию performOperation. В performOperation, lock вызывается снова, хотя task1 не покинул критический раздел через вызов unlock();.

В деталях результатов для дефекта вы видите последовательность инструкций, ведущих к дефекту. Например, вы видите, что после первого входа в критический раздел, путь выполнения:

  • Вводит функцию performOperation.

  • Внутренние performOperation, пытается войти в тот же критический раздел еще раз.

Можно кликнуть каждое событие, чтобы перейти к соответствующей линии в исходном коде.

Коррекция - Снимите второй замок

Одной из возможных коррекций является удаление вызова на lock в task1.



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++
По умолчанию: On
Синтаксис командной строки: DOUBLE_LOCK
Влияние: Высокий
ИДЕНТИФИКАТОР CWE: 764
Введенный в R2014b