Инструкции по записи Thread-Safe S-функций

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

Фон

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ресурсы

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

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

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

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

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

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

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

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

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

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

  • Замените входящие вызовы функций на входящие эквиваленты. Для примера замените strtok с strtok_r.

mexCallMATLAB

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

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

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

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

Исключение Бесплатный код

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

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

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

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

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

Гонка данных

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

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

Приложение может иметь неожиданное поведение.

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

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

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

Изменчивый

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

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

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

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

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

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

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

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

Используйте thread-safe ssSetLocalErrorStatus, и ssGetLocalErrorStatus функций. Не используйте ssSetErrorStatus и ssGetErrorStatus.

См. также

|

Похожие темы