2016-08-05 2 views
2

Предположим, у меня есть микроконтроллер с основным контуром и прерыванием 1 миллисекунды (если вы не знаете, что это такое, это просто задача, которая прерывает выполнение основного цикла, а что-то делает ..... и это прерывание 1 миллисекунды, потому что это происходит каждые миллисекунды).Частично изменчивая переменная?

У меня есть переменная, которую я использую для обмена данными между основной петлей и прерывания миллисекунды:

volatile status_t Status; 

Сейчас у меня есть часть кода в главном цикле, который обновляет переменную Status, которая делает тонна преобразований на нем:

cli(); // This temporarily turns off interrupts, so we don't 
      // modify the variable unsafely 
Status.UpdateStuff(); 
Status.UpdateOtherStuff(); 
//etc. 

sei(); // Turn interrupts back on 

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

Одним из возможных решений этой проблемы заключается в следующем:

cli(); 
status_t* localStatus = (status_t*)&Status; 
localStatus->UpdateStuff(); 
localStatus->UpdateOtherStuff(); 
//etc. 

Status = *localStatus; 
sei(); 

Реальный вопрос здесь заключается в следующем:

ли это будет делать то, что я надеюсь, что он будет делать, или есть лучший способ, чтобы получить вокруг вопроса о постоянном обновлении переменной вместо того, чтобы позволить оптимизатору кэшировать переменную?

+0

Во втором фрагменте я предполагаю, что вы имеете в виду '& Status'. Кстати, я не думаю, что есть намного лучшие альтернативы. –

+0

Задайте задания таймера в очереди, а основной поток прочитает очередь и обработает задания. В операциях очереди вам нужно только мьютекс. –

+0

@MatteoItalia Yup, это то, что я имел в виду ... – DarthRubik

ответ

3

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

cli(); 
status_t localStatus = Status; 
localStatus.UpdateStuff(); 
localStatus.UpdateOtherStuff(); 
... 
Status = localStatus; 
sei(); 
+0

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

0

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

cli(); 
do { 
    auto lastStatus = Status; 
    sei(); 

    auto nextStatus = lastStatus; 
    nextStatus.UpdateStuff(); 
    nextStatus.UpdateOtherStuff(); 
    ... 

    cli(); 
} while (lastStatus != Status); 
Status = nextStatus; 
sei(); 
Смежные вопросы