exponenta event banner

CERT C: POS51-C правил

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

Описание

Определение правила

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

Внедрение Polyspace

Эта проверка проверяет взаимоблокировку.

Примеры

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

Проблема

Взаимоблокировка возникает, когда несколько задач застряли в своих критических секциях (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).

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

Риск

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

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

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

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

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

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

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

Пример - Взаимоблокировка с двумя задачами


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();
 } 
}

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

ВыборСпецификация
Настройка многозадачности вручную
Точки входа

task1

task2

Детали критического разделаЗапуск подпрограммыЗавершение процедуры
begin_critical_section_1end_critical_section_1
begin_critical_section_2end_critical_section_2

Взаимоблокировка возникает, поскольку команды могут выполняться в следующей последовательности:

  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();
 } 
}

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

ВыборСпецификация
Настройка многозадачности вручную
Точки входа

task1

task2

task3

Детали критического разделаЗапуск подпрограммыЗавершение процедуры
lock1unlock1
lock2unlock2
lock3unlock3

Взаимоблокировка возникает, поскольку команды могут выполняться в следующей последовательности:

  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();
 } 
}

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

Группа: Правило 50. POSIX (POS)
Представлен в R2019a

[1] Данное программное обеспечение было создано компанией MathWorks и включает в себя следующие компоненты: «Веб-сайт SEI CERT-C», © 2017 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

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

Данное программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллона или его Институтом разработки программного обеспечения.