Дважды разблокируйте

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

Описание

Дважды разблокируйте, происходит когда:

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

  • Вызовы задачи соответствие разблокировали функциональный my_unlock.

  • Задача вызывает my_unlock снова. Задача не вызывает my_lock во второй раз между двумя вызовами my_unlock.

В многозадачном коде функция блокировки начинает критический раздел кода, и разблокировать функция заканчивает его. Когда задача, task1 вызывает функцию блокировки my_lock, другие задачи, вызывая my_lock, должна ожидать до вызовов task1 соответствие разблокировало функцию. 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 BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);

void task1(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

void task2(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

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

ОпцияЗначение
Configure multitasking manually
Tasks (-entry-points)

task1

task2

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

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

 polyspace-bug-finder
   -entry-points task1,task2
   -critical-section-begin BEGIN_CRITICAL_SECTION:cs1
   -critical-section-end END_CRITICAL_SECTION:cs1

task1 вводит критический раздел через вызов BEGIN_CRITICAL_SECTION();. task1 оставляет критический раздел через вызов END_CRITICAL_SECTION();. task1 вызывает END_CRITICAL_SECTION снова без промежуточного вызова BEGIN_CRITICAL_SECTION.

Исправление — удаляет второй, разблокировали

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



int global_var;

void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);

void task1(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
    global_var += 1;
}

void task2(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

Исправление — удаляет, сначала разблокировали

Если вы хотите, чтобы второй global_var+=1; был в критическом разделе, одно возможное исправление должно удалить первый вызов END_CRITICAL_SECTION.



int global_var;

void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);

void task1(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    global_var += 1;
    END_CRITICAL_SECTION();
}

void task2(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

Исправление — добавляет другую блокировку

Если вы хотите, чтобы второй global_var+=1; был в критическом разделе, другое возможное исправление должно добавить другой вызов BEGIN_CRITICAL_SECTION.



int global_var;

void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);

void task1(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

void task2(void)
{
    BEGIN_CRITICAL_SECTION();
    global_var += 1;
    END_CRITICAL_SECTION();
}

Проверяйте информацию

Группа: параллелизм
Язык: C | C++
Значение по умолчанию: на
Синтаксис командной строки: DOUBLE_UNLOCK
Влияние: высоко
ID CWE: 765

Введенный в R2014b