• MQTT/UDP, предвесенние итоги: дистанционная конфигурация и цифровая подпись

      Зима кончается, и это повод подвести очередную черту и рассказать, что нового появилось в MQTT/UDP.

      Для начала, ссылки на предыдущие введение и статью.

      Спасибо всем, кто с интересом отреагировал и отдельно тем, кто делился мыслями. Вы мне очень помогли с подходом к цифровой подписи. Итак, что изменилось по крупному:

      • Появился механизм гибкого расширения протокола: Tagged Tail Records, TTRs
      • На его базе сделана схема цифровой подписи пакетов
      • Сделан механизм дистанционной конфигурации компонент
      • Поднят полный цикл CI: сборка, юнит-тесты, сквозные тесты протокола (4*4 языка программирования)
      • Реализация на Си теперь поддерживает разные архитектуры и умеет интегрироваться с разными ОС и мониторами.
      • Есть публичные пакеты для Питона и Луа, хотя, конечно, они уже устарели.

      Ну и многое по мелочи: интеграция с OpenHAB, конфиг-файлы и логгинг, проверка совместимости с облачным MQTT сервисом, сделан тестовый пример для Wemos D1 (NodeMCU), сделан тестовый пример для atmega128+ethernet (не ардуино), сделан пример протокольного коннектора на Яве (CCU825), сделан пример информера-контроллера в desktop tray (наконец-то я могу включать свет в комнате в два клика мышки:), и ещё разное.

      Теперь по порядку.
      Читать дальше →
      • +19
      • 3,7k
      • 2
    • С новым годом, с новым MQTT/UDP

        Привет.

        Как я уже писал недавно (Первая краткая статья о MQTT/UDP), MQTT/UDP — протокол на базе MQTT, но:

        • Ходит поверх UDP broadcast (не нужен брокер, почти не нужна конфигурация)
        • До неприличия простой в реализации (10 строк на си + UDP/IP стек — и вы отправляете данные с сенсора)
        • Все слышат всех

        В некотором смысле это CAN, но поверх Ethernet-а.

        Зачем.
        Читать дальше →
      • Проще, чем MQTT? MQTT/UDP

          Хотел написать на эту тему подробную статью, но, очевидно, руки не доходят. Посему краткое сообщение. Я разработал и реализовал на нескольких языках в виде прототипного кода версию протокола MQTT под рабочим названием MQTT/UDP. Для нетерпеливых и тех, кому уже всё понятно и очевидно, код на Гитхабе

          Зачем

          Я живу в квартире, которая почти полностью управляется собственной системой умного дома несколько лет. Управление светом, климатом, датчики, лёгкая автоматизация, вот это всё.

          За это время я выяснил (да, впрочем, и до того понимал), что главное свойство систем УД — надёжность.

          Все системы с центральным узлом по определению ненадёжны. Отсюда — желание получить интерконнект компонент системы (а их в реальном умном доме много) без использования какого-либо центрального хаба.
          Читать дальше →
        • DZ Online Tech: ABBYY. Как не запутаться в нейронных сетях?

            Мы (DZ Systems) уже второй год снимаем серию передач о цифровой трансформации. Обычно это передачи «про бизнес», в основном ориентированные на топ-менеджеров и призванные помочь разобраться в бизнес-ценности того, что называется цифровая трансформация.

            Но в этом году снимаем так же и вторую «линейку» передач — DZ Online Tech, теперь уже ориентированную на технологические аспекты той же темы. Если коротко — о том, что находится «под капотом».

            Ниже — расшифровка очередной такой передачи, в которой мы с Иваном Ямщиковым (Яндекс, ABBYY, да и вообще профессионал высокого класса) говорим о применении нейронных сетей в современном мире.

            Если интересно, можно посмотреть и саму передачу.

            А для тех, кто любит читать — расшифровка ниже:

            — Здравствуйте. Наш сегодняшний гость – Иван Ямщиков из компании ABBYY, который
            расскажет нам как устроен современный искусственный интеллект.
            По отношению к AI условно есть две позиции: люди, которые говорят: «Мы не хотим
            ничего понимать про суть происходящего в системе. У нас есть статистические методы,
            которые сами вынут модель из внешней жизни. Эта модель будет правильной, она будет
            чувствовать все семантические тонкости». И есть люди, которые говорят: «Нет, так
            нельзя. Мы же понимаем, что происходит. Мы это понимание должны вложить в систему
            искусственного интеллекта, и тогда она будет ценнее, лучше и качественнее». Эта битва
            имеет внутри себя какие-то критерии?


            — Давай я объясню на менее философском языке. Есть люди, которые говорят: «Нам нужны более
            сильные, более производительные алгоритмы и бОльшие объёмы данных. Мы возьмём более
            производительный алгоритм, и он на бОльшем объёме даст нам бОльшее качество целевой
            метрики, неважно какой». Я не знаю людей, которые говорят, что им не нужны данные или
            алгоритмы. Поэтому у второй группы людей, на мой взгляд, подход следующий: «Помимо
            всего этого нам бы неплохо ещё человеческой разметки в том или ином виде, какое-то
            экспертное знание, добавить поверх».
            Читать дальше →
          • DZ Online Tech: Postgres Professional

              Привет.

              В прошлом году я начал снимать серию передач/интервью на тему цифровой трансформации бизнеса (они тут, кому интересно — подписывайтесь). Эти передачи были на стыке IT и бизнеса, но, всё же, больше про бизнес.

              В процессе стало понятно, что есть немало тем, которые имеют существенную глубину с программерской точки зрения. И в этом году мы начали снимать серию интервью под общим лейблом «DZ Online Tech» — теперь уже с упором на то, что под капотом. Ну и поскольку видео всем смотреть лень, конечно, эти интервью расшифровываются, и сегодня я публикую первое — с Иваном Панченко из Postgres Professional.

              Кому интересен оригинал — вот он:


              (Ну и, кстати, я не могу поклясться, что все выпуски будут выходить в расшифровке, так что если понравилось — подписывайтесь на ютубе, туда всё приходит раньше и гарантированно.)

              Для тех, кто любит читать — расшифровка:
              Читать дальше →
            • Колибри для Фантома

                Краткое содержание: разработка модуля совместимости с ОС Колибри внутри модуля совместимости с ОС Юникс внутри ОС Фантомь)

                Внутри ОС Фантом есть маленький простенький Юникс. POSIX подсистема. В принципе необязательная для работы самого Фантома и довольно неполная — Unix Quake под ней собрать удалось, а, например, апач не соберётся почти наверняка. Тем не менее — она есть.

                Чтобы продолжить, надо понимать, что такое ОС Колибри. Колибри — обрусевший западный проект микро-операционки на ассемблере. Собственно, это описание довольно полно. Над Колибри работают фанаты программирования на ассемблере x86, она, соответственно, непереносима и, к сожалению, очень плохо спроектирована. Очень — это катастрофически. Для понимания масштаба бедствия — нет никакого общего механизма определения успешности или ошибочности системного вызова. Для некоторых определить несупех просто невозможно, некоторые вызовы возвращают свой личный набор кодов ошибок, некоторые — какой-то другой.

                Почему же, тем не менее, любопытно реализовать слой совместимости с этой ОС? Тому несколько причин:

                • Она очень компактна. Забегая вперёд — первую программу для Колибри в Фантоме удалось запустить через четыре часа работы.
                • Этот мини-проект стал драйвером развития некоторых нативных подсистем Фантома,
                  в частности — оконной.
                • Главное — всё состояние процесса Колибри, известное ядру, укладывается в небольшую структуру. Многие (почти все!) вызовы — stateless, то есть не опираются о какое-либо знание,
                  хранимое в ядре. Это идеальный кандидат на реализацию персистентных (переживающих перезапуск ОС) бинарных (не написанных на байткод-языке) процессов в Фантоме.
                Читать дальше →
                • +27
                • 3,6k
                • 6
              • Фантом: большая сборка мусора

                  Эта статья — продолжение, начало здесь. Для тех, кто не кликнул на ссылку, краткая вводная:

                  Мы обсуждаем сборку мусора в операционной системе Фантом, то есть в среде виртуальной (байткод-) машины, работающей в персистентной оперативной памяти. Размер персистентной памяти — порядка размера диска, то есть единицы терабайт на сегодня и, потенциально, десятки и сотни терабайт завтра.

                  Поскольку речь идёт о виртуальной памяти, то существенная часть объектов в любом случае находится не в оперативной памяти, независимо от того, какой алгоритм и вообще подход мы избрали. То есть — стоимость доступа к объекту велика. Это, в общем случае, дисковая операция.

                  Кроме того, следует ожидать, что в сетевой среде совокупности таких виртуальных машин будут обмениваться прокси-объектами, то есть будет существовать граф объектов, растянутый на много машин в сети и, конечно, во всём этом кошмаре потенциально потребуется уметь собирать мусор не только на одной машине, но и по сети.

                  Принятая мной идея схемы сборки мусора в такой среде выглядит как совокупность двух сборщиков.
                  Читать дальше →
                • Драйверы умного или виртуального железа

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

                    Для начала введём определение bus master: устройство, способное быть не только ведомым, но и ведущим на шине компьютера. То есть — не только отвечать на транзакции ввода-вывода, инициированные процессором, но и самостоятельно их инициировать — по собственной инициативе «ходить» в память.

                    История таких устройств уходит корнями в понятие DMA: ещё во времена прародителя микропроцессоров, микропроцессора 8080 (КР5080ИК80), появилось понимание, что процессор хорошо бы разгрузить от рутинной операции перетаскивания байтиков между устройствами в-в и памятью.
                    Читать дальше →
                    • +13
                    • 10,5k
                    • 6
                  • UDP/TCP File System, Trivial Remote File System

                      Сегодня выходной, так что напишу коротко про мелочи, до которых, как правило, руки не доходят.

                      TCP FS



                      Есть ещё одна вещь, которой нет в современном Юниксе и которую я хочу иметь в unix box фантома. Она проста как мычание, и почему её никто не сделал — непостижимо:

                      #cat /tcp/host/port > local_file
                      


                      Правда, я хочу использовать иной синтаксис имени файла, URL style — tcp://host:port, но это уже детали. Естественно, наравне с TCP просится UDP, и там вообще проблем нет.

                      Заголовок спойлера
                      Вообще unix-подсистема Фантома «ест» как традиционные Юниксовые имена, /usr/include/stdio.h, так и URL-и, tcp://ya.ru:80.


                      Для TCP есть очевидная проблема — нужен ли нам listen или connect, но её можно решить через указание в имени «файла» определённого суффикса.

                      Сказать на эту тему настолько больше нечего, что перейдём без остановки к следующей.

                      TRFS — тривиальная дистанционная файловая система.


                      Читать дальше →
                    • Lazy threads: опциональный параллелизм

                        Статья-гипотеза. Описанное нигде не было реализовано, хотя, в принципе, ничто не мешает запилить такое в Фантоме.

                        Эта идея пришла мне в голову очень давно и даже где-то была мной описана. Триггер к тому, чтобы её описать сегодня — обсуждение сетевых драйверов Линукса в комментариях к Анатомии драйвера.

                        Сформулирую проблему, описанную там, как я её понимаю: сетевой драйвер Линукса работает в отдельной нити, которая читает принятые пакеты из устройства и синхронно их обрабатывает. Прогоняет через роутинг, файрволл и, если пакет не нам, отправляет его в исходящий интерфейс.

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

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

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

                        Как это.
                        Читать дальше →
                      • Анатомия драйвера

                          Опять вернёмся в традиционную область разработки операционных систем (и приложений для микроконтроллеров) — написание драйверов.

                          Я попробую выделить некоторые общие правила и каноны в этой области. Как всегда — на примере Фантома.

                          Драйвер — функциональная компонента ОС, ответственная за отношения с определённым подмножеством аппаратуры компьютера.

                          С лёгкой руки того же Юникса драйвера делятся на блочные и байт-ориентированные. В былые времена классическими примерами были драйвер диска (операции — записать и прочитать сектор диска) и драйвер дисплея (прочитать и записать символ).

                          В современной реальности, конечно, всё сложнее. Драйвер — типичный инстанс-объект класса, и классов этих до фига и больше. В принципе, интерфейс драйверов пытаются как-то ужать в прокрустово ложе модели read/write, но это самообман. У драйвера сетевой карты есть метод «прочитать MAC-адрес карты» (который, конечно, можно реализовать через properties), а у драйвера USB — целая пачка USB-специфичных операций. Ещё веселее у графических драйверов — какой-нибудь bitblt( startx, starty, destx, desty, xsize, ysize, operation ) — обычное дело.

                          Цикл жизни драйвера, в целом, может быть описан так:

                          • Инициализация: драйвер получает ресурсы (но не доступ к своей аппаратуре)
                          • Поиск аппаратуры: драйвер получает от ядра или находит сам свои аппаратные ресурсы
                          • Активация — драйвер начинает работу
                          • Появление/пропадание устройств, если это уместно. См. тот же USB.
                          • Засыпание/просыпание аппаратуры, если это уместно. В контроллерах часто неиспользуемая аппаратура выключается для экономии.
                          • Деактивация драйвера — обслуживание запросов прекращается
                          • Выгрузка драйвера — освобождаются все ресурсы ядра, драйвер не существует.


                          (Вообще я написал в прошлом году черновик открытой спецификации интерфейса драйвера — см. репозиторий и документ.)

                          Мне известны три модели построения драйвера:

                          • Поллинг
                          • Прерывания
                          • Нити (threads)

                          Читать дальше →
                        • Персистентная ОС: ничто не блокируется

                            Это — статья-вопрос. У меня нет идеального ответа на то, что здесь будет описано. Какой-то есть, но насколько он удачен — неочевидно.

                            Статья касается одной из концептуальных проблем ОС Фантом, ну или любой другой системы, в которой есть персистентная и «волатильная» составляющие.

                            Для понимания сути проблемы стоит прочесть одну из предыдущих статей — про персистентную оперативную память.

                            Краткая постановка проблемы: В силу того, что прикладная программа в ОС Фантом персистентна (не перезапускается при перезагрузке), а ядро — нет (перезапускается при перезагрузке и может быть изменено между запусками), в такой системе нельзя делать блокирующие системные вызовы. Обычным способом.
                            Читать дальше →
                          • Атрибуты устройств, или ioctl must die

                              В процессе работы над ОС Фантом, которая вообще не Юникс никаким местом, мне, тем не менее, захотелось сделать в нём Unix-compatible подсистему. Не то, чтобы прямо POSIX, но что-то достаточно близкое. Отчасти из любопытства, отчасти для удобства, отчасти как ещё один migration path. (Ну и вообще было интересно, насколько трудно написать простенький Юникс «из головы».) В качестве цели номер 1 была поставлена задача запустить quake 1 for Unix, которая и была достигнута.

                              В процессе, естественно, появились open/close/r/w/ioctl, и появилось ощущение, что последний неприлично, постыдно устарел. В качестве упражнения для размятия мозга я реализовал (в дополнение к обычному ioctl) некоторый альтернативный API, который бы позволил управлять свойствами устройств более гибким и удобным с точки зрения пользователя способом. Этот API, конечно, имеет свои очевидны минусы, и, в целом, эта статья — RFC, aka request For Comments.

                              Итак, API на уровне пользователя:

                              // returns name of property with sequential number nProperty, or error
                              errno_t listproperties( int fd, int nProperty, char *buf, int buflen );
                              
                              errno_t getproperty( int fd, const char *pName, char *buf, int buflen );
                              errno_t setproperty( int fd, const char *pName, const char *pValue );
                              


                              Правила:

                              1. Никаких дефайнов с номерами, только имена.
                              2. Никаких бинарных данных, только строки

                              Читать дальше →
                            • От шедулера к планировщику

                                См. две другие статьи этой группы — Делаем многозадачность и Преемптивность: как отнять процессор.

                                Сразу просьба к строгим читателям. Если вы не поняли какой-либо термин из применённых — спросите, я подскажу, что я имел в виду. А если вам нравится другое написание или перевод этого термина — укажите его в комментарии. Я применяю те, которые нравятся мне.

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

                                Как я уже говорил, шедулер — это просто функция, которая отвечает на вопрос: какую нить и на сколько времени поставить на процессор.

                                Кстати, в SMP системе шедулер ничем не отличается от однопроцессорного. Вообще, чтобы проще понимать структуру взаимодействия сущностей на одном и нескольких процессорах, проще всего представить себе следующую модель: для каждого процессора есть нить «простоя» (которая работает, если вообще больше некому и просто останавливае процессор до прерывания), которая постоянно пытается «отдать» процессор (которым она как бы владеет) другим нитям, выбирая нить с помощью шедулера.

                                Говоря о шедулере нельзя не сказать о приоритетах.

                                Приоритет — свойство нити (или процесса) влияющее на конкуренцию этой нити с другими нитями за процессор.

                                Приоритет обычно описывается парой <класс приоритета, значение приоритета внутри класса>.
                                Читать дальше →
                              • Преемптивность: как отнять процессор

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

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

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

                                  Но, как обычно, есть нюансы. См. код для интела.

                                  Сам «отъём» процессора делается как в рамках обычного хардверного прерывания, обычно — по таймеру, так и в рамках «софтверного» прерывания — которое, собственно, такое же прерывание, но вызванное специальной инструкцией процессора. Такой способ переключения контекста нужен, если мы (например, в рамках примитива синхронизации) явно останавливаем нить и не хотим ждать, пока прилетит таймерное прерывание.
                                  Читать дальше →
                                • Делаем мультизадачность

                                    Я стараюсь чередовать статьи про разработку ОС вообще и специфические для ОС Фантом статьи. Эта статья — общего плана. Хотя, конечно, я буду давать примеры именно из кода Фантома.

                                    В принципе, реализация собственно механизма многозадачности — довольно простая вещь. Сама по себе. Но, во-первых, есть тонкости, и во-вторых, она должна кооперироваться с некоторыми другими подсистемами. Например, та же реализация примитивов синхронизации очень тесно связана с реализацией многозадачности. Есть небанальная связь так же и с подсистемой обслуживания прерываний и эксепшнов. Но об этом позже.

                                    Начнём с того, что есть два довольно мало связанных модуля — собственно подсистема переключения задач (контекстов) и подсистема шедулинга. Вторую мы сегодня обсуждать почти не будем, просто опишем кратко.

                                    Шедулер — это функция, которая отвечает на вопрос «какой нити отдать процессор прямо сейчас». Всё. Простейший шедулер просто перебирает все нити (но, конечно, готовые к исполнению, не остановленные) по кругу (RR алгоритм). Реальный шедулер учитывает приоритеты, поведение нити (интерактивные получают больше, чем вычислительные), аффинити (на каком процессоре нить работала в прошлый раз) и т.п., при этом умеет сочетать несколько классов приоритетов. Типично это класс реального времени (если есть хотя бы одна нить этого класса — работает она), класс разделения времени и класс idle (получает процессор только если два предыдущих класса пустые, то есть в них нет нитей, готовых к исполнению).

                                    На сём пока про шедулер закончим.

                                    Перейдём к собственно подсистеме, которая умеет отнять процессор у одной нити и отдать его другой.
                                    Читать дальше →
                                  • Сборка мусора в персистентной модели: от терабайта и дальше

                                      Привет всем. Продолжу о Фантоме. Для понимания полезно прочесть статью про персистентную оперативку, а так же общую статью про Фантом на Открытых Системах. Но можно и так.

                                      Итак, мы имеем ОС (или просто среду, не важно), которая обеспечивает прикладным программам персистентную оперативную память, и вообще персистентную «жизнь». Программы живут в общем адресном пространстве с управляемыми (managed) пойнтерами, объектной байткод-машиной, не замечают рестарта ОС и, в целом, счастливы.

                                      Очевидно, что такой среде нужна сборка мусора. Но — какая?

                                      Есть несколько проблем, навязанных спецификой.

                                      Во-первых, теоретически, объём виртуальной памяти в такой среде огромен — терабайты, всё содержимое диска. Ведь мы отображаем в память всё и всегда.

                                      Во-вторых, нас категорически не устраивают stop the world алгоритмы. Если для обычного процесса остановка в полсекундны может быть приемлема, то для виртуальной памяти, которая, большей частью, на диске, это будут уже полчаса, а то как бы не полсуток!

                                      Наконец, если считать, что полная сборка мусора составляет полсуток, нас, наверное, это не устроит — было бы здорово иметь какой-то быстрый процесс сбора мусора, хотя бы и не полностью честный, пусть он часть мусора теряет, но если удаётся быстро вернуть 90% — уже хорошо.

                                      Тут нужна оговорка. Вообще говоря, в системе, которая располагает парой терабайт виртуальной памяти, это не так уж критично — даже если не делать освобождение памяти полсуток, возможно, не так много и набежит — ну, например, истратится 2-3, ну 5 гигабайт, ну даже и 50 гигабайт — не жалко, диск большой.

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

                                      Ок, итого у нас две задачи.
                                      Читать дальше →
                                    • Персистентная оперативная память

                                        Сегодня — рассказ про одну из ключевых концепций ОС Фантом. Впрочем, сама концепция, конечно, существовала и до Фантома — фактически, у Танненбаума в конце книги, там, где он позволяет себе фантазировать, просматриваются очертания почти всех особенностей Фантома, так что, в целом, подход довольно очевиден для тех, кто хотя бы задумывается о будущем систем вообще.

                                        Персистентная оперативка — очень простая и очень непростая вещь.

                                        В целом, всё просто: представьте себе, что содержимое оперативной памяти не пропадает. Никогда. Например, при выключении компьютера. Или, например, при… исчезновении компьютера. «И души умерших программ носятся над водою».

                                        Ну, действительно — неважно: если мы смогли спасти состояние компьютера перед его отключением, то можно восстановить это состояние в другом. Таком же. Вообще таком же? Прямо до микросхемы? А если в нём видеокарта другая — уже нельзя?

                                        Можно, потому что мы говорим не о том, чтобы заперсистить, сохранить всё состояние компьютера, а только его оперативную память. Но тогда в этом нет пользы, скажет внимательный читатель — уже хотя бы регистры надо бы сохранить? Иначе восстановление только памяти не позволит программе работать как если бы ничего не происходило.

                                        А задача — именно такова. Обеспечить программе среду, в которой остановка ОС и остановка компьютера для программы выглядели исключительно как нажатие на кнопку «пауза» при просмотре фильма. Во время паузы «под программой» можно даже компьютер поменять, но надо как-то обеспечить ситуацию, в которой продолжение работы для программы будет совершенно прозрачным.

                                        Это недостижимо, если требование доводить до абсолюта. Состояние хардвера сохранить и полностью восстановить нельзя. Но и не надо. Программе не нужна видеокарта, ей нужен тот же API и сохранённая картинка на экране, а это — можно.

                                        Что вырисовывается: сохранить состояние только оперативки — мало, а всего компьютера — нереально.

                                        Инженерная смекалка говорит нам, что нужно специфицировать для программы некоторую среду, которой во-первых, достаточно для самой программы, а во-вторых, в рамках такой среды должно быть возможно выполнить сохранение консистентного состояния программы и всего, что она «видит».
                                        Читать дальше →
                                      • Обзор примитивов синхронизации — спинлоки и тайны ядра процессора

                                          Последняя статья про классические примитивы синхронизации.

                                          (Наверное, потом напишу ещё одну про совсем уже нетипичную задачу, но это потом.)

                                          Сегодня мы немножко заглянем в процессор. Чуть-чуть.

                                          По сути, мы будем говорить про единственный примитив, который принципиально отличается от остальных: спинлок. Spinlock.

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

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

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

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

                                          Есть и ещё одно, семантическое различие. Мьютекс допускает и предполагает снятие нити с процессора, долгую остановку вызывающей нити. Мьютексом можно запереть объект на час или сутки, это приемлемо и нормально. Спинлок принципиально рассчитан только на кратчайшие приостановки, это всегда работа с неатомарным стейтом объекта. Присваивание группы переменных, небольшой цикл — это максимум того, что можно сделать под спинлоком.

                                          Итак, иерархия реализации такова: mutex/cond/sema сделаны на базе спинлоков, спинлоки — на базе атомарных операций, предоставляемых процессором. Мы в них немного заглянем сегодня.

                                          Как устроен спинлок?
                                          Читать дальше →
                                        • Обзор примитивов синхронизации — Семафор и немного lockless-а

                                            В прошлой заметке мы обсудили самую известную пару из лагеря инструментов синхронизации тредов — mutex и cond. Сегодня встретимся с sema — примитивом, который умеет заменять предыдущие два в одиночку.

                                            Но сначала — пара слов о случайных пробуждениях. (Спасибо xaizek, который мне об этом напомнил.) В принципе, строго реализованные механизмы синхронизации этим не страдают, но, тем не менее, опытный программист на это никогда не полагается.

                                            Напомню фрагмент кода:

                                            while(total_free_mem <= 0)
                                                {
                                                wait_cond(&got_free_mem, &allocator_mutex);
                                                }
                                            


                                            Здесь цикл вокруг wait_cond гарантирует нам, что даже если мы вернёмся из ожидания события случайно или по ошибке, ничего страшного не случится — проверка в while обеспечит нам уверенность, что нужное состояние проверяемого объекта достигнуто. Если нет — поспим ещё в ожидании.

                                            Отметим ещё раз, что проверяем мы состояние объекта (total_free_mem <= 0) при запертом мьютексе, то есть никто не может его менять в то же самое время.
                                            Читать дальше →