Средство поиска ошибки обнаруживает гонки данных между параллельными задачами. Используя аналитические опции Средства поиска Ошибки, можно зафиксировать обнаружение гонки данных путем указывания, что определенные задачи имеют более высокие приоритеты над другими. Задача с более высоким приоритетом является атомарной относительно задач с более низким приоритетом и не может быть прервана теми задачами.
Можно задать до четырех различных приоритетов с этими опциями (с самым высоким приоритетом, перечисленным сначала):
(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
и смотрите, обнаруживается ли гонка данных. Например:
Сконфигурируйте эти многозадачные опции:
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)