exponenta event banner

Рекомендации по написанию S-функций, безопасных для потоков

Simulink ® позволяет выполнять S-функции параллельно с многопоточным программированием, что делает моделирование более быстрым, чем последовательные запуски. Многопоточное программирование с использованием S-функций требует от вас обеспечения безопасности потока S-функций. Создание кода, защищенного от потоков, требует обеспечения защиты данных, совместно используемых несколькими потоками, с тем чтобы данные и результаты были такими, как ожидалось. Моделирование с S-функциями, не защищенными от потоков, может привести к неожиданному поведению.

Фон

C/C + + S-функции реализованы в C или C++ и встроены в общие библиотеки, известные как MEX-файлы. Когда блок S-функции относится к общей библиотеке, MATLAB ® загружает блок S-функции в процесс. Когда несколько S-функциональных блоков ссылаются на одну и ту же общую библиотеку, они также ссылаются на исходную копию общей библиотеки. Таким образом, многопоточные S-функциональные блоки одновременно получают доступ к одним и тем же данным .

Кроме того, если эти S-функции относятся к одним и тем же ресурсам, многопоточные S-функциональные блоки могут одновременно обращаться к одним и тем же ресурсам (например, к файлам), даже когда S-функциональные блоки связаны с различными S-функциями.

Рекомендации

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

Общий доступ к данным

ОпределениеПроблемаРешение

S-функция относится к данным с помощью указателей (например, ssSetUserData, ssGetUserData, ssSetPWorkValue и ssGetPWorkValue). S-функция легко совместно использует данные с помощью этих указателей.

Несколько потоков могут использовать указатели для доступа к одним и тем же данным. Если потоки одновременно пытаются выполнить запись в одну и ту же ячейку памяти, это нарушает безопасность потоков. Одновременные чтения из нескольких потоков безопасны, если нет записей до, во время или после чтения, что может вызвать некогерентные кэши.

Будьте осторожны при доступе к данным, совместно используемым несколькими потоками.

  • Сделать данные постоянными, если они доступны только для чтения.

  • Для контроля доступа к данным рекомендуется использовать мутексы. Mutexes также может обеспечить когерентность кэша.

Глобальные переменные

ОпределениеПроблемаРешение

Глобальные переменные являются общими данными, доступными во всем приложении.

Запись нескольких потоков в незащищенные общие данные небезопасна. Чтение безопасно, если нет записей до, во время или после чтения, что может вызвать некогерентные кэшы.

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

  • Если вы читаете, сделайте глобальную переменную постоянной.

Инициализация локальных статических переменных

ОпределениеПроблемаРешение

Локальные статические переменные хранятся в одном месте.

  • В C++ локальные статические переменные инициализируются при входе в область действия функции и не безопасны для потоков.

  • В C локальные статические переменные инициализируются в начале приложения до тех пор, пока значение справа от назначения (значение, присваиваемое переменной) является константой времени компиляции. Эти переменные безопасны для потоков.

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

  • Если вы используете версию C++ до C++ 11, защитите инициализацию локальной статической переменной с помощью мьютекса или механизма инициализации, защищенного от потоков, например std::call_once или boost::call_once.

  • Если используется C++ 11 или более поздняя версия, локальная статическая инициализация переменной гарантированно безопасна для потоков .

Ресурсы

ОпределениеПроблемаРешение

Ресурсы - это объекты, которые явно запрашиваются и возвращаются в систему. Некоторые примеры ресурсов включают динамически выделяемую память, файлы, подключения к базе данных и сетевые сокеты. Возможно, приложению потребуется управлять ресурсами.

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

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

Повторная входимость

ОпределениеПроблемаРешение

Функция повторно вводится, если безопасно вызывать несколько раз из одного потока (рекурсивно). Например, strtok функция не входит повторно, поскольку сохраняет некоторое внутреннее состояние строки, подлежащей токенизации. Функция повторно вводится, если она не вызывает неназначенные функции.

Вызов неназначенной функции из нескольких потоков может оказаться небезопасным.

Сделайте свою функцию новой. Например:

  • Устраните состояния, в которых находится функция.

  • Замените вызовы неназначенных функций на повторные эквиваленты. Например, заменить strtok с strtok_r.

mexCallMATLAB

ОпределениеПроблемаРешение

S-функция может вызвать MATLAB с помощью mexCallMATLAB функция.

Код симулятора, который обрабатывает mexCallMATLAB функция не защищена от потоков.

Не звонить mexCallMATLAB в вашей S-функции.

Свободный код исключения

ОпределениеПроблемаРешение

S-функция свободна от исключений до тех пор, пока ни одна из ее подпрограмм, при ее вызове, не обладает потенциалом прыжков в длину. Дополнительные сведения о свободных от исключений S-функциях см. в разделе Свободный от исключений код.

Когда S-функция не является свободной от исключений, ее подпрограммы косвенно вызываются через mexCallMATLAB, который не безопасен для потоков (см. mexCallMATLAB).

Проверьте свою S-функцию на наличие прыжков в длину. Если их нет, пометьте S-функцию как свободное исключение с помощью ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE) функция. Если S-функция прыгает в длину, несмотря на этот флаг, происходит непредсказуемое поведение.

Если S-функция создает исключение, но использует блок try/catch для обнаружения исключения, то эта S-функция является безопасной.

Гонка данных

ОпределениеПроблемаРешение

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

Возможно, приложение ведет себя непредвиденно.

Рассмотрим один из следующих вариантов:

  • Измените свой алгоритм, чтобы исключить гонки данных.

  • Используйте блокировки для управления порядком выполнения в критических частях кода или сделайте критические операции атомарными.

Изменчивый

ОпределениеПроблемаРешение

volatile ключевое слово указывает компилятору не оптимизировать переменную, поскольку ее значение может быть изменено каким-либо механизмом, о котором компилятор не знает.

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

Не используйте volatile ключевое слово для безопасности потоков.

Состояние ошибки

ОпределениеПроблемаРешение

Использование S-функций ssSetErrorStatus, ssGetErrorStatus, ssSetLocalErrorStatus, и ssGetLocalErrorStatus для доступа к статусу ошибки.

ssSetErrorStatus и ssGetErrorStatus не безопасны для потоков. Эти функции могут перезаписывать существующие ошибки и вызывать сообщения о неточных ошибках. Например, блок A может сообщить об ошибке, вызванной блоком B.

Использовать защиту от потоков ssSetLocalErrorStatus, и ssGetLocalErrorStatus функции. Не использовать ssSetErrorStatus и ssGetErrorStatus.

См. также

|

Связанные темы