Каков наилучший способ заблокировать все потоки, кроме одного? - PullRequest
2 голосов
/ 06 января 2020

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

Подскажите, пожалуйста, правильный ли мой подход к идее мьютекса или я должен использовать другой метод?

Редактировать: Я использую Keil RTX 5 / CMSIS RTOS 2 на чипе STM32H753

Спасибо

Ответы [ 3 ]

3 голосов
/ 13 января 2020

ОСРВ CMSIS имеет пару функций osKernelLock() и osKernelUnlock() - динамическое изменение приоритетов потоков или использование мьютексов не требуется и, вероятно, не рекомендуется.

Любая другая ОСРВ будет иметь похожую критическую секцию API.

Обратите внимание, что это только предотвращает переключение контекста задачи; это не препятствует запуску прерываний. Обычно это желательно, но если вы хотите предотвратить это, вы можете просто отключить все прерывания, используя _disable_irq() / _enable_irq(). Это предотвратит прерывания с переключением задач и .

Отключение прерываний - это грубая атака, которая в большей степени влияет на поведение вашей системы в режиме реального времени, чем даже блокировка планировщика. Как правило, это следует делать только в течение очень коротких периодов (как при блокировке планировщика).

0 голосов
/ 01 мая 2020

Не меняйте приоритеты ваших задач прямо из вашего кода пользователя. Большинство RTOS предоставляют API, которые позволяют нам делать это, но это плохой стиль, поскольку он порождает больше проблем, чем решит. Исключением является то, что некоторые RTOS функционируют для этого внутренне (например, мьютексы с наследованием приоритетов, чтобы избежать определенных многозадачных проблем).

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

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

управление уровнем запуска

Самый простой способ реализовать это - написать небольшую библиотеку поверх вашей ОСРВ, используя два подсчитывающих ресурса семафора: один для текущего уровня выполнения, другой для следующего. Когда вводится уровень выполнения, семафор заполняется столько токенов, сколько существует задач, которые должны находиться под контролем управления уровнем выполнения. Каждая задача, ожидающая обработки данного уровня выполнения, пытается получить свой токен из семафора current-runlevel . Когда задание завершило свою часть уровня выполнения, оно получает доступ к семафору следующего уровня *1016*, который в это время будет недоступен.

Перед заполнением конфигурации управления уровня выполнения вы можете нарисовать себе диаграмма последовательности , чтобы проверить, в каких точках задачи должны ждать других по любой причине. Обычно для каждой задачи релевантными являются лишь немногие уровни выполнения - и для каждого уровня выполнения набор соответствующих задач также может быть небольшим. Поэтому вы можете захотеть добавить небольшую вспомогательную функцию, например WaitForRunlevelNumber(N) с al oop, которая автоматически обрабатывает те несоответствующие уровни запуска.

Управление уровнем запуска должно заканчиваться sh, если все фазы, которые требуют явного Синхронизация закончена. Затем все задачи освобождаются. Иногда вы хотите выпустить задачи с низким приоритетом раньше, если они уже завершили все критические фазы. Тогда количество поддерживаемых задач может уменьшиться с одного уровня выполнения до следующего.

0 голосов
/ 06 января 2020

Какую ОСРВ вы используете? Я предполагаю, что вы используете ОСРВ на основе приоритетов.

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

Если вы хотите, чтобы один поток выполнялся исключительно, сделайте этот поток потоком с наивысшим приоритетом. Планировщик RTOS запустит поток с наивысшим приоритетом, который готов к запуску. Если ваш поток имеет наивысший приоритет и не блокирует себя, другие потоки не будут работать. В CMSIS-RTOS вы можете изменить приоритет потока с помощью osThreadSetPriority().

...