exponenta event banner

Гонка данных, включая атомарные операции

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

Описание

Этот дефект возникает в следующих случаях:

  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)Запуск подпрограммыЗавершение процедуры
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 выполняется одновременно с операцией чтения 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++
По умолчанию: Откл.
Синтаксис командной строки: DATA_RACE_ALL
Воздействие: среднее
CWE ID: 366, 413
Представлен в R2014b