Data race including atomic operations

Несколько задач выполняют незащищенные операции с общей переменной

Описание

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

  1. Несколько задач выполняют незащищенные операции с общей переменной.

  2. По меньшей мере одна задача выполняет операцию записи.

Если вы проверяете на этот дефект, вы можете увидеть гонки данных как на атомарных, так и неатомных операциях. Чтобы увидеть гонки данных только на неатомных операциях, выберите Data race. Bug Finder рассматривает операцию как атомарную, если ее можно выполнить в одной машинной инструкции. Для образца операция:

int var = 0;
может выполняться в одной машинной инструкции для целей, где размер int меньше, чем размер слова на целевом объекте (или размер указателя). См. «Определение атомарных операций в многозадачном коде». Если вы не хотите использовать это определение атомарных операций, включите эту проверку.

Чтобы найти этот дефект, перед анализом необходимо задать опции многозадачности. См. Многозадачность. Если ваш код вообще не использует критические разделы, чтобы избежать маркировки слишком многих операций, эта проверка отключена. Чтобы пометить гонки данных, включающие только атомарные операции, используйте опцию -force-data-races.

Риск

Гонка данных может привести к непредсказуемым значениям общей переменной, потому что вы не управляете порядком операций в различных задачах.

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

Чтобы исправить этот дефект, защитите операции с общей переменной с помощью критических разделов, временного исключения или других средств. См. «Защита общих переменных в многозадачном коде».

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

Примеры

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

#include<stdio.h>

int var;

void begin_critical_section(void);
void end_critical_section(void);

void task1(void) {
    var = 1;
}

void task2(void) {
    int local_var;
    local_var = var;
    printf("%d", local_var);
}

void task3(void) {
    begin_critical_section();
    /* Operations in task3 */
    end_critical_section();
}

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

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

task1

task2

task3

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

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

 polyspace-bug-finder
   -entry-points task1,task2,task3
   -critical-section-begin begin_critical_section:cs1
   -critical-section-end end_critical_section:cs1

В этом примере операция записи var=1; в task1 задач выполняется одновременно с операцией read local_var=var; в task2 задач.

task3 использует критический раздел, который можно повторно использовать для других задач.

Коррекция - Размещение операций в критическом разрезе

Одной из возможных коррекций является размещение этих операций в том же критическом разделе:

  • var=1; в task1

  • local_var=var; в task2

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

Для реализации критического раздела повторно используйте уже существующий критический раздел в task3. Поместите две операции между вызовами в begin_critical_section и end_critical_section.



#include<stdio.h>

int var;

void begin_critical_section();
void end_critical_section();

void task1(void) {
    begin_critical_section();
    var = 1;
    end_critical_section();
}

void task2(void) {
    int local_var;
    begin_critical_section();
    local_var = var;
    end_critical_section();
    printf("%d", local_var);
}

void task3(void) {
    begin_critical_section();
    /* Operations in task3 */
    end_critical_section();
}
Коррекция - Делайте задачи временно эксклюзивными

Еще одна возможная коррекция - сделать задачи task1 и task2 временно эксклюзивный. Временные исключающие задачи не могут выполняться одновременно.

На панели Configuration задайте следующие дополнительные опции:

ОпцияЗначение
Temporally exclusive tasks (-temporal-exclusions-file)task1 task2

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

 polyspace-bug-finder
     -temporal-exclusions-file "C:\exclusions_file.txt"
где файл C:\exclusions_file.txt имеет следующую линию:
task1 task2

Информация о результатах

Группа: Параллелизм
Язык: C | C++
По умолчанию: Off
Синтаксис командной строки: DATA_RACE_ALL
Влияние: Средний
ИДЕНТИФИКАТОР CWE: 366, 413
Введенный в R2014b