Как стать автором
Обновить

Комментарии 27

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

Я возможно не прав, но правильную архитектуру можно спроектировать тогда, когда вы подобное уже строили, при этом условия рынка остались неизменными.
Есть у кого то из великих, вроде бы у Кнутта, фраза «Лучшее, что может случиться с программистом, это когда он теряет все исходники готовой и работающей программы и вынужден писать ее заново, но уже зная, как это должно быть сделано»
Даже если это ваша цитата, все-равно не плохо, пусть и с оговорками :). Собственно в значительной мере начальный успех Open Source движения как раз в этом и заключался (90-е годы). Переписывали софт, который кто-то когда-то уже сделал.
А потом начальство сообразит, что можно декомпилировать бинарники, и будет тот же архитектурный ужас, только еще имена локальных переменных теперь все __CS_jnfdUYGioj_1 да Ss$8nNcLxzaD, а приватные методы называются m1(), m2(), m3()

Ужасно, как можно на такой элементарный вопрос написать столько текста.
Ну и


Ну и напоследок — как выделить младший бит числа (не знаю, зачем это может потребоваться, но вдруг пригодится)
define LowerBit(N) ((((N) — 1) ^ (N)) & (N)).

define LowerBit(N) ((N) & 1)

А то что у вас — это не младший бит, а младший единичный бит.

Ну и напоследок — как выделить младший бит числа (не знаю, зачем это может потребоваться, но вдруг пригодится)
define LowerBit(N) ((((N) — 1) ^ (N)) & (N)).


Для этого есть более короткая и понятная запись: #define LowerBit(N) (-(N) & (N))
Если бы я раз за разом на гитхабе не натыкался на элементарные ошибки, я бы не стал писать такой длинный текст. В этом посте я постарался объяснить, почему надо делать так, а не иначе.
Ну и конечно же, младший значащий бит, спасибо за правку.

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


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

Так что правильное смещение индекса должно выглядеть как-то так: https://github.com/nin-jin/go.d/blob/lock-free/source/jin/go.d#L261

Вы совершенно правы, я рассматривал достаточно простые архитектуры, а в продвинутых надо гарантировать порядок, но я предпочитаю барьеры атомикам.
я предпочитаю барьеры атомикам

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

volatile int Counter = 0;
Counter = (++Counter) % (Max+1);


и именно такой код мы можем видеть в множестве (то есть весьма часто) случаев. Что тут неправильного

Неопределённое поведение, школьный пример.
например, ссылочная очередь

это что за зверь?
Список с указателями на голову и хвост.
связаный список?
НЛО прилетело и опубликовало эту надпись здесь
Каким образом компилятор тут поможет? Расстановкой по барьеру после каждой инструкции?
НЛО прилетело и опубликовало эту надпись здесь
Если не работать со внешними для процессора устройствами, то конечно.
Если определить typedef uint8_t Counter_t; то компилятор сгенерит беззнаковое сравнение и вернем 255
register Counter_t Tmp;
Tmp = (Counter — 1);
if (Tmp < 0)
По-моему, компилятор просто выкинет if (Tmp < 0) как недостижимое для беззнакового числа.
В любом случае логика работы получается другая, Tmp = Max; недостижимо = warning компилятора. Привет PVS-studio :)
Уж Оочень грязный код.
Автор поста откомпилить пробовал свой код? Или все ошибки которые ниже — в именах типов, переменных — копирайт?
Конечно же, пробовал, но с определенными ограничениями. Поскольку меня интересует порождаемый код, то я смотрю ассемблер в godbolte, и, конечно же, там у меня множество пробных фрагментов с именами i,t и t1… а потом начинаю тащить это все в текст и красиво оформлять и бывают косяки, поскольку из текста обратно в компилятор для проверки уже на затаскиваю.
Так что Вы абсолютно правы, промежуточная переменная имеет знаковый тип, сейчас исправлю.
Тогда получается, что мы ограничиваем буфер 127 элементами.
Ну да, Вы правы, ограничит, правильным поведением компилятора будет анализ переноса, а не знакового разряда, но как этого добиться на С, я не знаю.
Вариант просто проверять значение нужного бита в SREG (ну и наплевать на переносимость с AVR заодно) не подходит?
Ну очень не хочется делать библиотеку зависимой.
Вот этот подход не совсем понимаю — гнаться за переносимостью между архитектурами. В тексте Вы боретесь за такты и байты, следующим традиционным шагом является архитектурозависимый код с кучей #ifdef'ов для переносимости. В туториале это лишнее, а в эксплуатации вполне разумно.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории