синхронизация данных без использования semapore в C

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

Любая помощь будет оценена

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

Это не относится к процедурам обслуживания прерываний – они не будут прерваны никаким планированием streamов (если вообще, а только другими прерываниями), но выполняются до тех пор, пока они не вернутся. Поэтому, если ISR ожидает ждать семафора (или аналогичного механизма, как вы просили), мы находимся в тупике, поскольку stream, содержащий его, не может быть запланирован больше, чтобы вернуть семафор …

Так что вам нужен совершенно другой механизм!

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

Как? Ну, OS / hardware specific – пока вы не предоставляете более подробную информацию, я здесь …

Еще несколько намеков: максимально сократить срок прерывания прерываний и убедиться, что общедоступные данные объявлены изменчивыми!

Это, вероятно, так же просто, как это в вашем основном коде:

disable_interrupts(); value += 1; enable_interrupts(); 

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

Вам нужен атомный доступ к данным. Если это единственная переменная, и вы можете гарантировать, что доступ является атомарным, этого достаточно. Тем не менее, это включает в себя дизассемблирование кода C и просмотр того, что у вас получилось. И даже если машинный код оказался атомарным (одна инструкция), он не будет переносимым.

Если у вас есть современный компилятор с поддержкой C11, вы можете объявить общую переменную как _Atomic и это решит проблему.

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

Универсальным «лучшим» решением может быть создание семафора самостоятельно. Пример:

 // volatile to prevent dangerous compiler optimizations; does not solve re-entrancy volatile uint32_t data; volatile bool guard; void ISR (void) { if(!guard) { data = SOME_REGISTER; } } void main (void) { ... guard = true; uint32_t local = data; guard = false; } 

В приведенном выше примере ни один атомный доступ не гарантируется вообще, даже не для guard переменной. Однако он больше не нужен, потому что в точке, где main() собирается читать данные, гарантированно устанавливается guard . Если прерывание запустится во время чтения, это не повредит данные.

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

(Обратите внимание, что этот код не приводит к «барьерам памяти», поэтому на сложных многоядерных процессорах этот метод может не работать, и volatile не обязательно приведет к барьеру памяти. На обычных микроcontrollerах это будет работать очень хорошо, хотя.)