Перейти к содержанию
    

Как Си работает с 16бит переменной, при прерываниях?

Уже давно пишу различный софт на С, и только сейчас меня пробило на один вопрос.

Есть переменная, int ( Больше 1 байта),

volatile integer I;

 

и мы пишем прогу, на какой нибудь 8-битный контроллер.

Естественно, любые операции с этой переменной осуществляются с помощью нескольких команд MCU.

Например:

I = I++;

соответствует:

1. - ADD Il,1

2. - ADD Ih,Carry

 

Так вот, пусть I используется и в основной программе и в прерывании. Компилятор должен учитывать возможность того, что прерывание может произойти в перерыве между 1 и 2 командой, и соответственно

значение I будет неправильным в этот момент.

Из всего вышеперечисленного следует, что компилятор запрещяет прерыввания на момент расчета нового значение I. Так ли это?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я так и предполагал, поэтому всегда запрещал прерывания на момент просчета.

Но просто подумал, что может это лишнее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1. - ADD Il,1

2. - ADD Ih,Carry

Так вот, пусть I используется и в основной программе и в прерывании. Компилятор должен учитывать возможность того, что прерывание может произойти в перерыве между 1 и 2 командой, и соответственно

значение I будет неправильным в этот момент.

 

Для этого есть sig_atomic_t. .

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я так и предполагал, поэтому всегда запрещал прерывания на момент просчета.

Но просто подумал, что может это лишнее.

 

Можно применить к переменной идентификатор volatile, тогда уже

у компилятора будет голова болеть, как корректно обращаться с этой

переменной.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

А Вы могли бы огласить эти три способа ?

Я тоже знаю несколько способов для разных ситуаций,

можно было бы объеденить знания/подходы :beer:

 

 

Можно применить к переменной идентификатор volatile, тогда уже

у компилятора будет голова болеть, как корректно обращаться с этой

переменной.

Вы первые строчки первого поста то прочитали ?

volatile значит только то, что при каждой операции нужно считать/записать результат из/в

место хранения переменной, причем таких операций в одном выражении может быть несколько,

и чтение/запись будет каждый раз...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А Вы могли бы огласить эти три способа ?
Для чтения:

1а) если известно, что прерывания в этот момент разрешены: запретить прерывания, считать, разрешить прерывания

1б) если известно, что прерывания в этот момент запрещены: считать.

1в) если неизвестно, разрешены ли прерывания:

1в-1) запомнить состояние прерываний в локальной переменной, считать, восстановить разрешение прерываний из локальной переменной.

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

2) считать значение, считать снова, сравнить, если не совпали - взять последнее значение за образец и считать снова и так пока не совпадет.

3) использовать промежуточную буферную переменную и флаг, разрешающий/запрещающий прерыванию писать в эту переменную в разных вариантах.

 

Для записи - те же 1a-1в и вариации на тему 3 (например, 2 буферные переменные и флаг, указывающий в какой из буферных переменных последнее полностью обновленное значение).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для чтения:

1а) если известно, что прерывания в этот момент разрешены: запретить прерывания, считать, разрешить прерывания

1б) если известно, что прерывания в этот момент запрещены: считать.

1в) если неизвестно, разрешены ли прерывания:

1в-1) запомнить состояние прерываний в локальной переменной, считать, восстановить разрешение прерываний из локальной переменной.

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

2) считать значение, считать снова, сравнить, если не совпали - взять последнее значение за образец и считать снова и так пока не совпадет.

3) использовать промежуточную буферную переменную и флаг, разрешающий/запрещающий прерыванию писать в эту переменную в разных вариантах.

 

Для записи - те же 1a-1в и вариации на тему 3 (например, 2 буферные переменные и флаг, указывающий в какой из буферных переменных последнее полностью обновленное значение).

Да, у меня те же способы, только в варианте 3 есть некоторая вариация, которая

приспособлена для работы с несколькими такими переменными,

используется однобайтовая volatile переменная, которая при этом вне прерываний

доступна только с атомарным доступом(однотактовым),

при этом всегда можно проконтролировать для конкретной переменной было ли прерывание

в процессе обращения к ней.

 

Но больше всего мне нравится вариант N2...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как-то сложно у вас, ребята...

Я пытаюсь представить, на каких контроллерах и с какой системой прерываний могут потребоваться варианты 2 и 3, и не нахожу среди используемых. К счастью. :)

Вы народ то не пугайте.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вспомнил еще один вариант, правда довольно экзотический....

Прерывание анализирует стек и выясняет было ли оно вызвано в момент

доступа к такой многобайтовой переменной, ну и если нужно подправляет стек или

выставляет флаг невалидности результата доступа.

Такой вариант используется например при обработке исключений,

правда писать эту часть обработчика нужно на ASM.

 

 

Как-то сложно у вас, ребята...

Я пытаюсь представить, на каких контроллерах и с какой системой прерываний могут потребоваться варианты 2 и 3, и не нахожу среди используемых. К счастью. :)

Вы народ то не пугайте.

Вариант N2 например, нужен в ситуации когда в системе есть одно прерывание и

даже временный запрет прерываний является нежелательным тк может приводить к значительному

джиттеру.

P.S.Мы говорим о многобайтовых переменных не ограничиваясь только 16бит переменной

на 8 бит контроллере...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вспомнил еще один вариант, правда довольно экзотический....

Прерывание анализирует стек и выясняет было ли оно вызвано в момент

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

 

Что-то я не могу себе представить, как по стеку можно определить, обращается ли в данный момент программа к определённой переменной... Разве что обращение к переменной оформить в виде подпрограммы, и проверять адрес возврата на стеке? Что-то больно сложно выходит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то я не могу себе представить, как по стеку можно определить, обращается ли в данный момент программа к определённой переменной... Разве что обращение к переменной оформить в виде подпрограммы, и проверять адрес возврата на стеке? Что-то больно сложно выходит.
Я же сказал что немного экзотический...

Но Вы в своем вопросе сами и ответили, действительно один из вариантов

по адресу доступа к соответствующей подпрограмме,

при этом можно подправить стек так что бы доступ к переменной начался заново с

safe point... ну и это на самом деле не так уж и сложно...

 

Такой прием используется например при обработке исключений FPU, только там

обычно на стеке нужно править так чтобы инструкция, вызвавшая прерывание, больше

не вызывалась, и при этом был удобоваримый результат.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

на каких контроллерах и с какой системой прерываний могут потребоваться варианты 2 и 3
Например у ARM в THUMB режиме накладные расходы на запрет/разрешение прерываний могут оказаться выше, чем на трехкратное чтение переменной и сравнение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А Вы могли бы огласить эти три способа ?

Я тоже знаю несколько способов для разных ситуаций,

можно было бы объеденить знания/подходы :beer:

Вы первые строчки первого поста то прочитали ?

volatile значит только то, что при каждой операции нужно считать/записать результат из/в

место хранения переменной, причем таких операций в одном выражении может быть несколько,

и чтение/запись будет каждый раз...

 

А вы по какой книжке С учили? Или может быть С++?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...