Средство поиска ошибки обнаруживает гонки данных между параллельными задачами. Используя аналитические опции Средства поиска Ошибки, можно зафиксировать обнаружение гонки данных путем указывания, что определенные задачи имеют более высокие приоритеты над другими. Задача с более высоким приоритетом является атомарной относительно задач с более низким приоритетом и не может быть прервана теми задачами.
Можно задать до четырех различных приоритетов с этими опциями (с самым высоким приоритетом, перечисленным сначала):
(nonpreemptable) прерывания: Используйте опцию Interrupts (-interrupts)
.
(Выгружаемые) прерывания: Используйте опции Interrupts (-interrupts)
и -preemptable-interrupts
.
Циклические (nonpreemptable) задачи: Используйте опции Cyclic tasks (-cyclic-tasks)
и -non-preemptable-tasks
.
Можно также задать выгружаемые нециклические задачи с опцией Entry points (-entry-points)
и -non-preemptable-tasks
.
Циклические (выгружаемые) задачи: Используйте опцию Cyclic tasks (-cyclic-tasks)
.
Можно также задать нециклические задачи с опцией Entry points (-entry-points)
.
Например, прерывания имеют самый высокий приоритет и не могут быть вытеснены другими задачами. Чтобы задать класс прерываний, которые могут быть вытеснены, понизьте их приоритет путем создания их выгружаемыми.
Рассмотрите этот пример с тремя задачами. Переменная var
совместно используется этими двумя задачами task1
и task2
без любой защиты, такими как критический раздел. В зависимости от приоритетов task1
и task2
, Средство поиска Ошибки показывает гонку данных. Третья задача не важна для примера (и добавляется только, чтобы включать критический раздел, в противном случае обнаружение гонки данных отключено).
int var; void begin_critical_section(void); void end_critical_section(void); void task1(void) { var++; } void task2(void) { var=0; } void task3(void){ begin_critical_section(); /* Some atomic operation */ end_critical_section(); }
Настройте приоритеты task1
и task2
и смотрите, обнаруживается ли гонка данных. Например:
Сконфигурируйте эти mulitasking опции:
Interrupts (-interrupts)
: Задайте task1
и task2
как прерывания.
Cyclic tasks (-cyclic-tasks)
: Задайте task3
как циклическую задачу.
Critical section details (-critical-section-begin -critical-section-end)
: Задайте begin_critical_section
как функцию, начинающую критический раздел и end_critical_section
как функция, заканчивающая критический раздел.
Запустите средство поиска ошибки.
Вы не видите, что данные мчатся. Поскольку task1
и task2
являются nonpreemptable прерываниями, к совместно используемой переменной нельзя получить доступ одновременно.
Измените task1
на выгружаемое прерывание при помощи опции -preemptable-interrupts
.
Запустите Средство поиска Ошибки снова. Вы теперь видите, что данные мчатся на совместно используемой переменной var
.
Измените этот пример следующими способами и смотрите эффект модификации:
Измените приоритеты task1
и task2
.
Например, можно оставить task1
как nonpreemptable прерывание, но изменить task2
на выгружаемое прерывание при помощи опции -preemptable-interrupts
.
Гонка данных исчезает. Причина:
task1
имеет более высокий приоритет и не может быть прерван task2
.
Операция в task2
является атомарной и не может быть прервана task1
.
Включите средству проверки Data race including atomic operations
(не включенный по умолчанию). Используйте опцию Find defects (-checkers)
.
Вы видите, что данные мчатся снова. Средство проверки рассматривает все операции как потенциально неатомарные, и операция в task2
может теперь быть прервана более высокой приоритетной операцией в task1
.
Попробуйте другие модификации к аналитическим опциям и смотрите результат средств проверки.
-non-preemptable-tasks
| -preemptable-interrupts
| Cyclic tasks (-cyclic-tasks)
| Interrupts (-interrupts)