Семафор не очень подходит, если нужно пробудить все ждущие потоки (логика manual reset event), а mutex+cond лично мне кажется избыточным, когда нужен флаг-событие. В WinAPI, к примеру, нет такого синхронизационного объекта как condition variable, эта абстракция реализуется на этой платформе с использованием event-а или семафора.
Подскажите, почему Вы не рассматриваете event как отдельный примитив синхронизации OS?
Известные мне реализации condition не умеют работать сами по себе без мьютекса, а вот event вполне себе может.
wiki
Без блокировок (англ. lock-free)
Для алгоритмов без блокировок гарантируется системный прогресс по крайней мере одного потока. Например, поток, выполняющий операцию «сравнение с обменом» в цикле, теоретически может выполняться бесконечно, но каждая его итерация означает, что какой-то другой поток совершил прогресс, то есть система в целом совершает прогресс.
Если код разросся до такого состояния, что существует куча логики с использованием блокировок в непонятных ситуациях, тогда lock-free алгоритмы точно не помогут такому коду, т.к. эти алгоритмы в разы сложнее алгоритмов с блокировками.
Я бы рекомендовал придерживаться нескольких правил, чтобы избежать взаимных блокировок:
1) мьютекс должен блокировать доступ к данным, а не код (если это возможно)
2) никогда не вызывайте внешний код из под блокировки (коллбеки и т.п.)
3) в идеале lock/unlock должны происходить в одной функции (RAII)
Проблемму фрагментации памяти в Windows решает технология Low-Fragmentation Heap, которая включена по умолчанию начиная с Vista, а в XP включается через WinAPI
Пример с надписью «Last Updated» это не плацебо, а правдивая информация.
Автоматическое обновление скрыто от глаз и не понятно как оно работает, и работает ли вообще, по этому дополнительная информация о времени последнего обновления привносит ясность.
В свое время меня так достала политика МТС, что я достал симку с телефона и разломал ее на четыре части, не взирая на то, что это был основной номер на протяжении шести лет.
>>rebase'ни его относительно master'а, squash'ни свои коммиты и попинай меня снова
Потому, что 'rebase' нужно делать через merge:
Делаем merge c веткой мастер, при этом происходит правильное слияние с учетом истории, также всегда создается новый коммит, по этому для того, чтобы откатить результат, достаточно перенести указатель ветки на один шаг назад.
После слияния ветка master будет являться началом Ваших изменений, rebase на master уже пройдет без конфликтов, можно делать squash, если того требует мэйнтейнер: rebase --interactive, либо вообще способ для ленивых reset --mixed и делаем новый коммит.
Важно: Если Вы знаете, что Ваши действия приведут к удалению оригинального коммита (как при rebase или reset) или если в чем-то не уверенны, сделайте резервный указатель (новый branch), к которому потом всегда можно будет вернуться.
Похоже на рефакторинг замена метода объектом методов, но только с какой-то кривой реализацией на статических переменных.
Данный рефакторинг имеет смысл, если у вас есть длинный метод, в котором локальные переменные так сильно переплетены, что это делает невозможным применение извлечения метода, то есть когда все настолько запущено, что другого выхода практически нет.
А если удалить только защитный слой, а амальгаму оставить, фоторамка не будет просвечиваться?
Кстати, недавно встречал видео рекламу на зеркалах в туалете (в Dream Town, Киев), удивило.
А чем Вас не устраивала «стандартного размера клавиатура», та, которая без надписей?
Мне на последней своей клавиатуре пришлось специально сдирать надписи лезвием…
Мартин Фаулер в своей книге уделяет большое внимание юнит тестам. Если код не покрыт юнит тестами, то рефакторинг такого кода становится опасным.
Хорошо бы упомянуть как-то этот момент на Вашем сайте, допустим в интерактивных примерах можно добавить шаг с запуском юнит тестов, и т.п.
У Вас ошибка в живом примере на Java refactoring.guru/replace-method-with-method-object:
В шаге 5 отсутствует замена локальных переменных приватным полями.
Хорошо бы добавить кнопку «Сообщить об ошибке».
А так сайт отличный, однозначно в избранное!
>> С++ даёт возможность контроля типов, один из инструментов для этого — шаблоны. Программу того аппарата можно было спроектировать так, что ошибка несогласованности систем мер и весов были бы невозможны.
Кто мешает завести различные типы для систем мер и весов, и зачем для этого применение шаблонов?
inject_as_object делает привязку к одной конкретной реализации, а что, если захочется иметь две разные реализации?
Также что делать, если нужно использовать разные параметры конструктора для разных клиентов?
Мне кажется более удобным и гибким решением делать inject на уровне объектов, а не классов.
>>Оказывается в трекере была установка — удалять неактивных пользователей
Я надеюсь, что после этого вы научились делать резервную копию базы пользователей?
REPL
Почему-то не вижу особого смысла для C++:
>>Для проверки какой-либо конструкции языка или его возможности Вы создаете полноценное тестовое приложение.
Если задача состоит в том, чтобы сделать какой-то эксперимент, можно сделать это в виде юнит-теста, у Вас ведь есть существующая инфраструктура для юнит-тестов? Такой подход даст возможность без особого труда поиграться с объектной структурой Вашего приложения. Ну а если нужно написать какой-то тест для проверки производительности чего-либо, то тут уже не обойтись без отдельного тестового приложения.
>>Для вычисления значения какого-либо сложного выражения, Вы долго мучаетесь с калькулятором…
Калькулятор на C++, а смысл? Думаю проще воспользоваться другими средствами.
Программисты создадут продукт для таких же программистов и этот продукт обычным людям будет не нужен.
Выбирать направление разработки должны бизнес аналитики, учитывая интересы компании и ее клиентов.
Спасибо, теперь стало немного понятней с LoadStore, хотя для реализации такого поведения нужен некий механизм задержки обработки store до завершения чтения, хотелось бы понять устройство такой логики на уровне архитектуры процессоров.
Я понимаю барьер StoreLoad следующим образом:
Допустим операция записи была выполнена через store buffer и данных пока еще нет в кеше. Для того, чтобы упорядочить последующую операцию чтения, данные из store buffer необходимо перенести в кеш линию. Тоесть результат предыдущей операции записи должен быть сохранен в кеше прежде, чем начнется операция чтения.
Большое спасибо за статью, я в первые начал немного понимать зачем нужны барьеры и как они работаю.
Единственное чего не могу понять, так это что такое Load/Store барьер, и как он реализован в схеме store buffer/invalidate queue. Ведь если операция чтения была произведена из ранее инвалидированной кеш линии, то дальнейшая обработка invalidate queue ни к чему не приведет. Или инструкция Load/Store обрабатывает invalidate queue перед выполнением чтения, то есть это будет комбинация read/write барьеров?
smp_rmb(); // барьер чтения
if (a == 0) // чтение
{
smp_wmb(); // барьер записи
b = 1; // запись
}
Было бы здорово разобрать примеры поведения двух процессоров в случаях Load/Store и Store/Load.
Хочу поделиться одной историей с моей жизни.
Дело было на моей первой работе после окончания института.
Взяли меня программистом в одну государственную контору в отдел АСУП
и выдали мне старенький компьютер, пока новый компьютер еще не заказали.
И все бы ничего, но этот старенький компьютер любил пререзагружатся сам по себе, и довольно часто.
В общем работать на нем было практически невозможно,
т.к. в любую минуту можно было потерять не сохраненные изменения.
В общем, в ожидании нового компьютера, я решил поиграть пока в Quake.
И вот, играя в Quake я замечаю, что компьютер то не перезагружается!
Я свернул Quake и поработал немного, компьютер по прежнему не перезагрузился.
В итоге мой рабочий день начинался так: прихожу я на работу,
включаю компьютер и быстро запускаю Quake пока компьютер не успел перезагрузится,
затем сворачиваю Quake и продолжаю работать.
Невероятно, но факт.