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

Запрос данных из задачи в задачу

23 минуты назад, Ozone сказал:

А разве volatile-флажок обеспечит атомарность операции изменения этого флажка?    По-моему, как минимум нужно флажок помещать вкритическую секцию.

"как минимум" - не надо. Можно без критических секций обойтись. Критическая секция - это уже тяжёлое решение. При решении практической задачи синхронизации, разумно начинать с простых решений.

PS: Хоть бы почитали всю тему что-ль? Чтобы на новый круг не заходить...

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


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

9 минут назад, jcxz сказал:

"как минимум" - не надо. Можно без критических секций обойтись. Критическая секция - это уже тяжёлое решение. При решении практической задачи синхронизации, разумно начинать с простых решений.

PS: Хоть бы почитали всю тему что-ль? Чтобы на новый круг не заходить...


Так я и прочитал всю тему.

volatile-флажок одно из простых решений.   Но возник вопрос: а разве так можно?    Флажок - это обычная переменная, общая для нескольких задач.  Не будет ли коллизий обращений к этому флажку, даже если он volatile?  

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


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

36 минут назад, Ozone сказал:

volatile-флажок одно из простых решений.   Но возник вопрос: а разве так можно?    Флажок - это обычная переменная, общая для нескольких задач.  Не будет ли коллизий обращений к этому флажку, даже если он volatile?  

О каких коллизиях речь?

Вот одна задача выполняет запись во флажок: flag = 1; другая - чтение флажка: if (flag) ....

char volatile flag;

Что вас тут смущает? И в чём тут неатомарность?

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


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

4 минуты назад, jcxz сказал:

Вот одна задача выполняет запись во флажок: flag = 1; другая - чтение флажка: if (flag) ....

Что вас тут смущает? И в чём тут неатомарность?

Так ведь у нас несколько задач могут инициировать запись во флажок.   
С rtos только начал разбираться.   В не rtos программе если есть volatile флажок, который может модифицироваться как в прерывании, так и в главном цикле, рекомендуется также включать критическую секцию, то бишь отключать прерывания, если флажок шире чем uint8_t   

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


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

33 минуты назад, Ozone сказал:

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

Это как решит программист. Флаг работает не сам по себе, а по алгоритму, реализуемому программистом. Сколько задач/читают и пишут в этот флаг и как они это делают - всё в руках погромиста.

33 минуты назад, Ozone сказал:

В не rtos программе если есть volatile флажок, который может модифицироваться как в прерывании, так и в главном цикле, рекомендуется также включать критическую секцию, то бишь отключать прерывания, если флажок шире чем uint8_t   

Стоит сперва включать голову. :wink: Чтобы придумать общий алгоритм работы программы. А флажки, задачи, критические секции и т.п. - это компоненты программы. Которыми она может жонглировать как угодно - как решит её создатель. Бездумно всегда включать критическую секцию, не понимая для чего и почему - плохая идея.

33 минуты назад, Ozone сказал:

если флажок шире чем uint8_t   

Это видимо вы читали что-то для 8-битных систем. Для которых операция записи переменных >1 байта - неатомарна.

Для ARM например все операции записи 8-, 16-, и 32-битных переменных - как правило атомарны (если не предпринимать спец.действий для их неатомарности).

Но зачем вам флажок разрядностью более минимально возможного записываемого элемента в архитектуре?

 

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

Или сперва обсудите - кто что будет делать? в каком порядке? какие инструменты использовать и для чего?

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

Программа начинается не с набивания строк типа char volatile ..., а с придумывания алгоритма работы, реализующего требуемый функционал.

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


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

volatile это для IO регистров, чтобы если сказали 10 раз запиши константу по этому адресу, то компилятор так и сделал. А для синхронизации это избыточно и не совсем то, более уместно использовать барьеры гарантирующие необходимый порядок операций с памятью.

Например для CM4 барьер это:

- инструкция (DMB) обеспечивающая порядок на аппаратном уровне;

- указание компилятору ("memory").

__STATIC_FORCEINLINE void __DMB(void)
{
  __ASM volatile ("dmb 0xF":::"memory");
}
Quote
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
 
"memory"

The "memory" clobber tells the compiler that the assembly code performs memory reads or writes to items other than those listed in the input and output operands (for example, accessing the memory pointed to by one of the input parameters). To ensure memory contains correct values, GCC may need to flush specific register values to memory before executing the asm. Further, the compiler does not assume that any values read from memory before an asm remain unchanged after that asm; it reloads them as needed. Using the "memory" clobber effectively forms a read/write memory barrier for the compiler.

Note that this clobber does not prevent the processor from doing speculative reads past the asm statement. To prevent that, you need processor-specific fence instructions.

Для IO области памяти упорядочивание обычно предусмотрено аппаратно без барьеров, но для флажка в SRAM это может быть важно (наверно возможны варианты с настрйоками MPU и кэширования).

Изменено пользователем amaora

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


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

27 минут назад, amaora сказал:

Например для CM4 барьер это:

- инструкция (DMB) обеспечивающая порядок на аппаратном уровне;

Конкретно DMB в Cortex-M бесполезна, т.к. ядро не умеет аппаратное переупорядочивание доступов на уровне шины к памяти.

Чуть полезнее DSB и ISB. DMB, скорее, для совместимости со старыми ARM исходниками.

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


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

42 минуты назад, amaora сказал:

volatile это для IO регистров, чтобы если сказали 10 раз запиши константу по этому адресу, то компилятор так и сделал. А для синхронизации это избыточно и не совсем то, более уместно использовать барьеры гарантирующие необходимый порядок операций с памятью.

И все-таки, тоже не совсем корректно. Volatile предписывает "неизвестный компилятору" побочный эффект доступа к объекту, а посему этот доступ (каким бы он ни был) не может быть отброшен или переупорядочен по отношению к другим таким доступам с неизвестными сайд-эффектами. Например, в коде

int value;
volatile int flag;

...

int main() {
  ...
  value = 10;
  flag  = 1;
}

компилятор вполне может выполнить присвоение value = 10 после flag = 1, даже если между этими строчками в коде имеется барьер памяти (барьер компилятора, он же барьер оптимизации). Но с большой долей вероятности в приведенном примере при оптимизации запись value = 10 вообще выкинется за ненадобностью.

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


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

9 minutes ago, Arlleex said:

компилятор вполне может выполнить присвоение value = 10 после flag = 1, даже если между этими строчками в коде имеется барьер памяти (барьер компилятора, он же барьер оптимизации)

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

Если value не используется и включена LTO, то наверно единственную запись в value можно выбросить и это будет корректно.

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


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

9 минут назад, amaora сказал:

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

Если value не используется и включена LTO, то наверно единственную запись в value можно выбросить и это будет корректно.

А как Вы объясните компилятору, что value не используется, если она в реальности все-таки используется, а компилятор "не додумал"? Для него записи/чтения из обычных не volatile-переменных не помечены наличием у них сайд-эффектов. Поэтому он может такие записи перемежать друг с другом и вполне выносить их после барьера памяти. Запросто.

К примеру, вот выдержка по поводу барьера памяти в компиляторе ARM CLang (ARM Compiler):

Цитата

__schedule_barrier intrinsic

This intrinsic creates a special sequence point that prevents operations with side effects from moving past it under all circumstances. Normal sequence points allow operations with side effects past if they do not affect program behavior. Operations without side effects are not restricted by the intrinsic, and the compiler can move them past the sequence point.

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


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

46 minutes ago, Arlleex said:

Для него записи/чтения из обычных не volatile-переменных не помечены наличием у них сайд-эффектов. Поэтому он может такие записи перемежать друг с другом и вполне выносить их после барьера памяти. Запросто.

Сайд-эффектом помечен барьер, все до чего "законно" без UB может дотянуться функция с неизвестной при компиляции реализацией (аналог барьера), не может быть переставлено вокруг барьера. Поэтому value запишется до барьера. Ну либо не запишется нигде, но я не уверен, что компиляторы могут это надёжно вывести.

https://godbolt.org/z/rP4W4Eq19

Spoiler
int value;
volatile int flag;

static inline void fence(void)
{
  __asm volatile ("":::"memory");
}

int main() {

  value = 10;
  fence();
  flag  = 1;

  return 2;
}

 

 

46 minutes ago, Arlleex said:

К примеру, вот выдержка по поводу барьера памяти в компиляторе ARM CLang (ARM Compiler):

Не похоже на барьер памяти, надо читать всю документацию чтобы понять.

Изменено пользователем amaora

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


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

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

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

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

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

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

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

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

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

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