-
- Да, интересно, а насколько легковесны такие вызовы (в тактах, например): fk0легенда(294 знак., 18.06.2020 15:47)
- Допустим, я хочу сделать в threadX логгер. Он будет писать в
кольцевой буфер в памяти, из которого медленно и печально будет
выпечатываться в компорт. Задача достаточно классическая.
Логгировать одновременно могут все потоки. Как сделать кольцевой
буфер -- понятно. В принципе он может быть реализован на
lockless-алгоритмах, но.... Но поскольку компорт медленный, то
буфер может быть в переполненном состоянии (регулярно), то потоки
пытающиеся писать в лог должны ожидать fk0легенда(1061 знак., 18.06.2020 14:15)
- Я бы использовал очередь, в потоке, который логирует ошибку dxWAk(447 знак., 18.06.2020 15:05, картинка)
- Собственно и вопрос-то в том как сделать самодельную очередь. Потому, например, что готовая очередь может по каким-то причинам не подходить. Например, работает только с сообщениями фиксированного размера. Да, можно пересылать указатели на сообщения, но тогда на каждое нужно выделять память. Кроме того, если очередь реализована, условно, через системный вызов -- то работа с такой очередью становится очень тяжёлой, по сравнению с другими примитивами синхронизации, которые по fk0легенда(213 знак., 18.06.2020 15:13)
- я не знаю за threadX но на тнео, фриртос итд так. abivan(788 знак., 18.06.2020 15:02)
- Тут есть принципиальная проблема, даже две, на шагах 2 и 8: ожидать
факта освобождения памяти в буфере может одновременно *несколько*
потоков. Пробудить ты должен один или все -- зависит от
стратегии... И одновременно с пробуждением поток должен захватить
мьютекс для операций с буфером. Кольцевой буфер существует как раз
чтоб предельно ускорить и упростить аллокацию -- других аллокаций
не нужно. Ну и раз ты использовал готовую очередь, то к чему тогда
вообще буфер? - fk0легенда(18.06.2020 15:20)
- пробуждать поток будет ось в зависимости от приоритета. мьютекс мне не нужен, ос очередью рулит. abivan(254 знак., 18.06.2020 15:54)
- Тут есть принципиальная проблема, даже две, на шагах 2 и 8: ожидать
факта освобождения памяти в буфере может одновременно *несколько*
потоков. Пробудить ты должен один или все -- зависит от
стратегии... И одновременно с пробуждением поток должен захватить
мьютекс для операций с буфером. Кольцевой буфер существует как раз
чтоб предельно ускорить и упростить аллокацию -- других аллокаций
не нужно. Ну и раз ты использовал готовую очередь, то к чему тогда
вообще буфер? - fk0легенда(18.06.2020 15:20)
- Бинарный семафор. Самый приоритетный из ожидающих проснется,
заберет семафор, проверит место. Если места достаточно - отправит
данные. Если недостаточно - снова встанет на этом же самом
семафоре. - LightElf(18.06.2020 15:01)
- A остальные что, будут вечно спать? Я забыл уточнить, но записи в
буфере не фиксированного размера (логгер -- текстовые строчки,
вроде очевидно). Да и посылаются в компорт может быть не по одной.
Вместо одной ушедшей можно 5 новых записать, и наоборот. Будить
нужно всех ожидающих. И потом, между моментом проверки (нет места)
и засыпанием на семафоре запросто могло появиться свободное место.
И наоборот, после получения сигнала семафора другой поток мог
занять всё своими fk0легенда(343 знак., 18.06.2020 15:41)
- У тебя привычка обобщать все по самое некуда :) И в этом самом
некуда - находить неразрешимые проблемы. Не бывает единого драйвера
под разные OS и радикально разное железо. LightElf(1187 знак., 18.06.2020 22:49)
- Я не обобщаю, я подвожу к сложности реализации такой элементарной
сущности как условная переменная. Без которой нормально задачу не
решить. Да, её можно построить на базе пары семафоров, причём один
нужен в TLS (а в ThreadX есть TLS?), или можно сделать как в SDL,
по семафору на каждого ждуна (что реально плохо выглядит когда их
много -- я уже как-то писал про это). В данной задаче можно
схалявить и сделать недоделку (не являющуюся полноценной условной
переменной, но fk0легенда(6968 знак., 19.06.2020 00:55, ссылка)
- Ну вот опять
за рыбу деньгипопытка найти единое универсальное решение. Первое, что стоит сказать - на мелких процессорах системный вызов, как правило, легкий по тактам. Второе, чаще всего есть возможность просто и дешево сделать короткую критическую секцию, например запретив прерывания. Третье, там обычно нет SMP. Все это меняет развесовку описанных тобою проблем. LightElf(948 знак., 19.06.2020 02:13)- А какое должно быть решение? Можно подумать, что какие-то
фундаментальные принципы в "computer science" чем-то отличны в
зависимости от фирмы выпустившей микропроцессор. Может и не UART
вовсе, а TCP/IP, и не микроконтроллер, а Core I9. Суть от этого не
меняется. А ты хочешь сказать, мол в зависимости от того какой
глубины UART в МК всё кардинально меняется... На верхнем уровне
абстракции ничего о реализации нижнего знать не положено. Принято,
что есть некий метод write, fk0легенда(1601 знак., 19.06.2020 02:49)
- Ну вот есть у тебя абстракция write, пользуй ее и не ломай голову
как она внутри устроена. Конкретная реализация write будет зависеть
от OS, а конкретная реализация драйвера UART - от конкретного
железа. А если не UART, а Ethernet - там будут другие реализации и
другие драйвера. Будет ли там условная переменная, два семафора или
отдельный сопроцессор с блекджеком и программистками - это вопрос
конкретной реализации, а не фундаментальных принципов. LightElf(2323 знак., 19.06.2020 12:42)
- В таком варианте вместо запрета прерываний следует использовать
мьютекс -- они для этого и существуют. Причём мьютексов связанных с
разными и независимыми защищаемыми наборами данных может быть
много, а флаг прерываний -- один всего. Мьютекс более эффективен.
Более того, запрещать прерывания более чем несколько тактов --
дичь! Вопрос же не как критическую секцию сделать, а как сделать
атомик (на основе которого уже можно сделать тот же мьютекс или
критическую секцию). fk0легенда(2371 знак., 19.06.2020 15:27)
- Ну так никто не запрещает реализовать атомик через запрет прерывания, если подходящих инструкций процессору не завезли. Получатся как раз те самые несколько тактов. В FreeRTOS-е можно блокироваться из критической секции, система отслеживает такую ситуацию. - LightElf(23.06.2020 16:32)
- Ввиду не установки драйвера rookie.sys на сервере сахары пост
читать можно только кликнув на него... - fk0легенда(19.06.2020 15:30)
- Имеешь в виду, что кнопочка "развернуть [под]ветку" не работает? У меня на старом FF 52 - тоже не работает. - Toчкa oпopы(19.06.2020 16:35)
- В таком варианте вместо запрета прерываний следует использовать
мьютекс -- они для этого и существуют. Причём мьютексов связанных с
разными и независимыми защищаемыми наборами данных может быть
много, а флаг прерываний -- один всего. Мьютекс более эффективен.
Более того, запрещать прерывания более чем несколько тактов --
дичь! Вопрос же не как критическую секцию сделать, а как сделать
атомик (на основе которого уже можно сделать тот же мьютекс или
критическую секцию). fk0легенда(2371 знак., 19.06.2020 15:27)
- Интересно, если использовать язык Rust, эти проблемы останутся? =AK=(58 знак., 19.06.2020 12:41)
- Ну вот есть у тебя абстракция write, пользуй ее и не ломай голову
как она внутри устроена. Конкретная реализация write будет зависеть
от OS, а конкретная реализация драйвера UART - от конкретного
железа. А если не UART, а Ethernet - там будут другие реализации и
другие драйвера. Будет ли там условная переменная, два семафора или
отдельный сопроцессор с блекджеком и программистками - это вопрос
конкретной реализации, а не фундаментальных принципов. LightElf(2323 знак., 19.06.2020 12:42)
- А какое должно быть решение? Можно подумать, что какие-то
фундаментальные принципы в "computer science" чем-то отличны в
зависимости от фирмы выпустившей микропроцессор. Может и не UART
вовсе, а TCP/IP, и не микроконтроллер, а Core I9. Суть от этого не
меняется. А ты хочешь сказать, мол в зависимости от того какой
глубины UART в МК всё кардинально меняется... На верхнем уровне
абстракции ничего о реализации нижнего знать не положено. Принято,
что есть некий метод write, fk0легенда(1601 знак., 19.06.2020 02:49)
- Ну вот опять
- Я не обобщаю, я подвожу к сложности реализации такой элементарной
сущности как условная переменная. Без которой нормально задачу не
решить. Да, её можно построить на базе пары семафоров, причём один
нужен в TLS (а в ThreadX есть TLS?), или можно сделать как в SDL,
по семафору на каждого ждуна (что реально плохо выглядит когда их
много -- я уже как-то писал про это). В данной задаче можно
схалявить и сделать недоделку (не являющуюся полноценной условной
переменной, но fk0легенда(6968 знак., 19.06.2020 00:55, ссылка)
- У тебя привычка обобщать все по самое некуда :) И в этом самом
некуда - находить неразрешимые проблемы. Не бывает единого драйвера
под разные OS и радикально разное железо. LightElf(1187 знак., 18.06.2020 22:49)
- A остальные что, будут вечно спать? Я забыл уточнить, но записи в
буфере не фиксированного размера (логгер -- текстовые строчки,
вроде очевидно). Да и посылаются в компорт может быть не по одной.
Вместо одной ушедшей можно 5 новых записать, и наоборот. Будить
нужно всех ожидающих. И потом, между моментом проверки (нет места)
и засыпанием на семафоре запросто могло появиться свободное место.
И наоборот, после получения сигнала семафора другой поток мог
занять всё своими fk0легенда(343 знак., 18.06.2020 15:41)
- Я бы использовал очередь, в потоке, который логирует ошибку dxWAk(447 знак., 18.06.2020 15:05, картинка)