В этом примере показано, как использовать преимущества выполнения многопоточного кода на многоядерном процессоре с использованием графического разбиения. В этом примере для создания многопоточного кода требуется Simulink ® Coder™.
Одной из целей проектирования на основе моделей является создание реалистичных моделей физических систем и моделирование этих моделей в реальном времени, например, для проверки контроллеров с использованием аппаратного обеспечения в цикле (HIL). Однако по мере добавления дополнительных функций в модель установки вычислительные требования могут превышать ресурсы, доступные для одноядерных систем обработки.
Разделение установки и контроллера на отдельные части является одним из способов удовлетворения вычислительных потребностей сложных моделей. Simulink ® позволяет разделить завод с помощью блоков модели, а затем назначить код, генерируемый каждой подмоделью, потокам для выполнения в реальном времени в системе HIL, такой как Simulink Real-Time™. Чтобы увидеть, как это работает, давайте используем наш хост-компьютер в качестве резервной системы для среды выполнения в реальном времени и создадим многопоточный код в реальном времени для следующей модели.
slexMulticoreSolverExample

На рисунке выше показано, что код, созданный для модели, разделен на два потока. В этом примере предполагается, что целью является симметричный многоядерный процессор, так что потоки не связаны с каким-либо конкретным ядром. Операционная система отвечает за оптимальное использование ядер при планировании выполнения потоков. В идеале для обеспечения максимальной гибкости число потоков (Nt) должно быть больше числа ядер (Nc). Дважды щелкните кнопку «Generate Code and Profile Report» для создания многопоточного кода, профилирования его выполнения и визуализации результатов. Визуализация показывает основную карту занятости того, как ядра использовались на каждом этапе выполнения. Видно, что потоки перемещаются по ядрам так, как это лучше всего считает планировщик операционной системы. Этот вид планирования является хорошим, когда операционной системе также необходимо запускать другие процессы.

Simulink ® Coder™ генерирует код так, что два потока могут выполняться одновременно и, возможно, на двух разных ядрах. Это означает, что значения сигналов для
и
должны быть синхронизированы между двумя потоками. Simulink ® предоставляет несколько возможностей для выполнения этого требования, как показано здесь:


Используя приведенный ниже сценарий, мы смоделируем и продемонстрируем эффект детерминированных режимов, чтобы понять, как Simulink ® управляет синхронизацией.
Эталонное решение (ode3) - Simulink ® конфигурируется для предоставления эталонного решения путем синхронизации данных на каждом основном и вспомогательном временном шаге.
Удержание нулевого порядка (Zero Order Hold) - каждый поток решает подсистему уравнений с помощью собственного решателя, синхронизируя данные только на основных временных шагах.
Линейная экстраполяция - в дополнение к режиму удержания нулевого порядка каждый решатель экстраполирует данные, используя линейные прогнозы для компенсации ошибок задержки данных.
Для большинства систем, в которых точки синхронизации являются гладкими, режим линейной экстраполяции обеспечивает хороший компромисс между узкими местами связи и численной точностью.
h = figure; hVal = ishold; hold on; mdl = 'slexMulticoreSolverExample'; dt = get_param(mdl, 'DataTransfer'); modes = { ... 'Ensure deterministic transfer (minimum delay)', ... 'None', 'k:', ... 'Ensure deterministic transfer (maximum delay)', ... 'Zero Order Hold', 'm', ... 'Ensure deterministic transfer (maximum delay)', ... 'Linear', 'b' ... }; for i=1:3:length(modes) dt.DefaultTransitionBetweenContTasks = modes{i}; dt.DefaultExtrapolationMethodBetweenContTasks = modes{i+1}; out = sim(mdl); plot(out.logsout.get('x1').Values.Time, ... out.logsout.get('x1').Values.Data, ... modes{i+2}); end legend('Reference solution (ode3)', ... 'Zero Order Hold Extrapolation', ... 'Linear Extrapolation');

close_system('slexMulticoreSolverExample',0); close_system('slexMulticoreSolverMdlref',0); if ~hVal, hold off; end delete(h);