Мертвая блокировка

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

Описание

Мертвая блокировка происходит, когда несколько задач застревают в своих критических разделах (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
Tasks (-entry-points)

task1

task2

Critical section details (-critical-section-begin -critical-section-end)Starting 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();
 } 
}

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

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

Введенный в R2014b