CERT C++: CON53-CPP

Избегайте мертвой блокировки путем привязки предопределенного порядка

Описание

Управляйте определением

Избегайте мертвой блокировки путем привязки предопределенного порядка. [1]

Примеры

развернуть все

Описание

Мертвая блокировка происходит, когда несколько задач застревают в своих критических разделах (CS) потому что:

  • Каждый CS ожидает другого CS, чтобы закончиться.

  • Форма критических разделов (CS) замкнутый цикл. Например:

    • CS № 1 ожидает CS № 2, чтобы закончиться, и CS № 2 ожидает CS № 1, чтобы закончиться.

    • CS № 1 ожидает CS № 2, чтобы закончиться, CS № 2 ожидает CS № 3, чтобы закончиться, и CS № 3 ожидает CS № 1, чтобы закончиться.

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

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

Риск

Каждая задача ожидает критического раздела в другой задаче закончиться и не может продолжить. Программа может заморозиться неопределенно.

Фиксация

Фиксация зависит от первопричины дефекта. Можно попытаться повредить циклический порядок между задачами одним из этих способов:

  • Запишите все критические разделы, вовлеченные в мертвую блокировку в определенной последовательности. Каждый раз, когда вы вызываете функции блокировки критических разделов в задаче, уважаете порядок в той последовательности. Смотрите пример ниже.

  • Если один из критических разделов, вовлеченных в мертвую блокировку, происходит в прерывании, попытайтесь отключить все прерывания во время критических разделов во всех задачах. Смотрите Disabling all interrupts (-routine-disable-interrupts -routine-enable-interrupts).

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

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

Пример - заходит в тупик с двумя задачами



void task1(void);
void task2(void);

int var;
void perform_task_cycle(void) {
 var++;
}

void begin_critical_section_1(void);
void end_critical_section_1(void);

void begin_critical_section_2(void);
void end_critical_section_2(void);

void task1() {
 while(1) {
    begin_critical_section_1();
    begin_critical_section_2();
    perform_task_cycle();
    end_critical_section_2();
    end_critical_section_1();
 } 
}

void task2() {
 while(1) {
    begin_critical_section_2();
    begin_critical_section_1();
    perform_task_cycle();
    end_critical_section_1();
    end_critical_section_2();
 } 
}

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

ОпцияСпецификация
Configure multitasking manually
Entry points

task1

task2

Critical section detailsStarting routineEnding routine
begin_critical_section_1end_critical_section_1
begin_critical_section_2end_critical_section_2

Deadlock происходит, потому что инструкции могут выполниться в следующей последовательности:

  1. task1 вызывает begin_critical_section_1.

  2. task2 вызывает begin_critical_section_2.

  3. task1 достигает инструкции begin_critical_section_2();. Поскольку task2 уже вызвал begin_critical_section_2, task1 ожидает task2, чтобы вызвать end_critical_section_2.

  4. task2 достигает инструкции begin_critical_section_1();. Поскольку task1 уже вызвал begin_critical_section_1, task2 ожидает task1, чтобы вызвать end_critical_section_1.

Исправление - следует за той же последовательностью блокировки в обеих задачах

Одно возможное исправление должно следовать за той же последовательностью вызовов, чтобы заблокировать и разблокировать функции и в task1 и в task2.



void task1(void);
void task2(void);
void perform_task_cycle(void);

void begin_critical_section_1(void);
void end_critical_section_1(void);

void begin_critical_section_2(void);
void end_critical_section_2(void);

void task1() {
 while(1) {
    begin_critical_section_1();
    begin_critical_section_2();
    perform_task_cycle();
    end_critical_section_2();
    end_critical_section_1();
 } 
}

void task2() {
 while(1) {
    begin_critical_section_1();
    begin_critical_section_2();
    perform_task_cycle();
    end_critical_section_2();
    end_critical_section_1();
 } 
}

Пример - заходит в тупик больше чем с Двумя задачами



int var;
void performTaskCycle() {
 var++;
}

void lock1(void);
void lock2(void);
void lock3(void);


void unlock1(void);
void unlock2(void);
void unlock3(void);

void task1() {
 while(1) {
    lock1();
    lock2();
    performTaskCycle();
    unlock2();
    unlock1();
 } 
}

void task2() {
 while(1) {
    lock2();
    lock3();
    performTaskCycle();
    unlock3();
    unlock2();
 } 
}

void task3() {
 while(1) {
    lock3();
    lock1();
    performTaskCycle();
    unlock1();
    unlock3();
 } 
}

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

ОпцияСпецификация
Configure multitasking manually
Entry points

task1

task2

task3

Critical section detailsStarting routineEnding routine
lock1unlock1
lock2unlock2
lock3unlock3

Deadlock происходит, потому что инструкции могут выполниться в следующей последовательности:

  1. task1 вызывает lock1.

  2. task2 вызывает lock2.

  3. task3 вызывает lock3.

  4. task1 достигает инструкции lock2();. Поскольку task2 уже вызвал lock2, task1 ожидает вызова unlock2.

  5. task2 достигает инструкции lock3();. Поскольку task3 уже вызвал lock3, task2 ожидает вызова unlock3.

  6. task3 достигает инструкции lock1();. Поскольку task1 уже вызвал lock1, task3 ожидает вызова unlock1.

Исправление — повреждает циклический порядок

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

  1. lock1

  2. lock2

  3. lock3

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



int var;
void performTaskCycle() {
 var++;
}

void lock1(void);
void lock2(void);
void lock3(void);

void unlock1(void);
void unlock2(void);
void unlock3(void);

void task1() {
 while(1) {
    lock1();
    lock2();
    performTaskCycle();
    unlock2();
    unlock1();
 } 
}

void task2() {
 while(1) {
    lock2();
    lock3();
    performTaskCycle();
    unlock3();
    unlock2();
 } 
}

void task3() {
 while(1) {
    lock1();
    lock3();
    performTaskCycle();
    unlock3();
    unlock1();
 } 
}

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

Группа: 10. Параллелизм (CON)

Введенный в R2019a


[1]  Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ-МЕЛЛОН И/ИЛИ ЕГО ИНСТИТУТА ПРОГРАММНОЙ ИНЖЕНЕРИИ СОДЕРЖАЛ, ЗДЕСЬ ПРЕДОСТАВЛЯЕТСЯ НА ОСНОВЕ "ASIS". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

Это программное обеспечение и сопоставленная документация не были рассмотрены, ни являются подтвержденным Университетом Карнеги-Меллон или его Институтом программной инженерии.