Задайте критические разделы с функциями, которые берут аргументы

При проверке многозадачного кода Polyspace® считает, что критический раздел находится между вызовами функции блокировки и разблокировки.

lock();
/* Critical section code */
unlock();

Группа операций в критическом разделе является атомарной относительно другой группы операций, которые находятся в том же критическом разделе (то есть имеют ту же функцию блокировки и разблокировки). См. также раздел «Определение атомарных операций в многозадачном коде».

Предположение Polyspace о функциях, определяющих критические сечения

Polyspace игнорирует аргументы в функциях, которые начинают и заканчивают критические сечения.

Для образца Polyspace рассматривает две секции кода ниже как один и тот же критический раздел, если вы задаете my_task_1 и my_task_2 в качестве точек входа, my_lock как функцию блокировки и my_unlock как функцию разблокировки.

int shared_var;

void my_lock(int);
void my_unlock(int);

void my_task_1() {
   my_lock(1);
   /* Critical section code */
   shared_var=0;
   my_unlock(1);
}

void my_task_2() {
   my_lock(2);
   /* Critical section code */
   shared_var++;
   my_unlock(2);
}

В результате анализ считает, что эти две секции защищены от прерывания друг друга, хотя они могут быть не защищены. Например, Bug Finder не обнаруживает гонку данных на shared_var.

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

Адаптируйте анализ Polyspace к функциям блокировки и разблокировки с помощью аргументов

Когда аргументы в функции, определяющие критические разделы, являются константами времени компиляции, можно адаптировать анализ, чтобы работать вокруг предположения Polyspace.

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

int shared_var;

void my_lock_1(void);
void my_lock_2(void);
void my_unlock_1(void);
void my_unlock_2(void);

void my_task_1() {
   my_lock_1();
   /* Critical section code */
   shared_var=0;
   my_unlock_1();
}

void my_task_2() {
   my_lock_2();
   /* Critical section code */
   shared_var++;
   my_unlock_2();
}

Если вы задаете my_lock_1 и my_lock_2 как функции блокировки и my_unlock_1 и my_unlock_2 как функции разблокировки, анализ распознает две секции кода как часть различных критических разделов. Например, Bug Finder обнаруживает гонку данных на shared_var.

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

  1. В заголовочном файле common_polyspace_include.h, преобразуйте аргументы функции в расширения имени функции с #define-с. В сложение предоставьте декларацию для новых функций.

    Для образца в предыдущем примере используйте эти #define-s и объявления:

    #define my_lock(X) my_lock_##X()
    #define my_unlock(X) my_unlock_##X()
    
    void my_lock_1(void);
    void my_lock_2(void);
    void my_unlock_1(void);
    void my_unlock_2(void);

  2. Укажите имя файла common_polyspace_include.h как аргумент для опции Include (-include).

    Анализ рассматривает этот файл заголовка как #include-d во всех анализируемых исходных файлах.

  3. Задайте новые имена функции как функции, начинающиеся и заканчивающие критические сечения. Используйте опции Critical section details (-critical-section-begin -critical-section-end).

См. также

Похожие темы