Самая строгая гарантия прогресса. Алгоритм работает без ожиданий, если каждая операция выполняется за детерминированное количество шагов, независящее от других потоков.
Без блокировок (lock-free)
Для алгоритмов без блокировок гарантируется системный прогресс по крайней мере одного потока. Например поток, выполняющий операцию сравнение с обменом в цикле теоретически может выполняться бесконечно, но каждая его итерация означает, что какой-то другой поток совершил прогресс, т.е. система в целом совершает прогресс.
Это не всегда очевидно, как конкретно стоит сделать, особенно когда сложная программа начинает вести себя непредсказуемо. Поэтому лучше всего использовать проверенные методики.
Вообще-то, термин «беззамочная» в литературе нигде не используется. В вашем случае CalculateSomethingAboutSystemColors использует lock-free алгоритм. Поэтому не стоит вводить людей в заблуждение. Речь идет не о «замках», а о локах, точнее об их отсутствии.
Я хотел следующее: по умолчанию заливается C неявно, но иногда я хочу явно заливать D. Такое возможно? Далее, хотелось бы, чтобы решение о том, что заливать неявно, находилось в cpp файле.
Все зависит от сложности задачи. Бывают настолько сложные системы, что просто так разрулить не получается. Предложенный подход эту проблему решает на корню. Это как с shared_ptr: можно его и не использовать и самому следить за памятью. Но зачем?
scoped_ptr нельзя копировать, поэтому нельзя контролировать время жизни подобно тому, как описано в статье. По поводу грабель вы правильно написали, но предложенный подход эти грабли убирает.
Отложенность вычислений для этого синглтона позволяет правильно разрулить зависимости при инициализации. Контроль времени жизни разруливает уничтожение.
Вы можете использовать вместо синглтона Майерса синглтон Александреску без каких-либо проблем. Я использовал наиболее простой способ для демонстрации идеи. Про многопоточность будет в другой статье.
Во-первых, предложенный класс An не может иметь синглтоном наследника, поэтому, как частный случай, T не может быть абстрактным. Во-вторых, An может использовать любую реализацию, которая заливается непосредственно в класс, а не обязательно синглтон (см. первую статью). В-третьих, нет отложенности вычислений, что вызовет проблемы с зависимостями.
Имелся ввиду подход, где не используется new и delete в явном виде, при этом объекты создаются в куче. Даже, например, в Java этого не видел, хотя там есть сборщик мусора, но везде и всюду разбросаны new .
Этот же комментарий был к первой статье. Приведу его еще раз:
«Речь в ней идет не о реализации, а об использовании… Можно взять реализацию из Александреску. Книжка его очень умная и толковая. Но вся статья написана о том, как использовать и убрать недостатки, присущие этому паттерну.»
Я, конечно, извиняюсь, но по-моему, так писать вообще не стоит. Зачем мне помнить, что где-то там надо освободить синглтон? К тому же такой подход содержит абсолютно все недостатки, которые указаны в первой статье.
Макросы я использовал, начиная с первой статьи. В принципе, можно обойтись и без них. Однако, в данном случае макросы являются чем-то вроде декларации и являются как бы частью интерфейса, дополняют класс в описательном стиле. Я не склонен думать, что макросы — это зло. Просто их надо правильно использовать.
Взять, например, макрос BIND_TO_SELF_SINGLE. Он говорит о том, что синглтон связывается сам с собой. Здесь мне не нужно знать, как этот макрос устроен. Мне нужно знать, что в результате получится. В последствии я могу заменить реализацию макроса (если потребуется), а все пользователи даже и не заметят этого. Таким образом, макросы выступают в роли интерфейса, как это ни странно.
Вообще-то, начиная с Windows Vista: InitializeSRWLock
Без ожиданий (wait-free)
Самая строгая гарантия прогресса. Алгоритм работает без ожиданий, если каждая операция выполняется за детерминированное количество шагов, независящее от других потоков.
Без блокировок (lock-free)
Для алгоритмов без блокировок гарантируется системный прогресс по крайней мере одного потока. Например поток, выполняющий операцию сравнение с обменом в цикле теоретически может выполняться бесконечно, но каждая его итерация означает, что какой-то другой поток совершил прогресс, т.е. система в целом совершает прогресс.
a=max(0, calculate_nominal_a());
У меня вопрос: а зачем используется InterlockedCompareExchangeRelease вместо InterlockedCompareExchange? Как-то об этом в статье не сказано ни слова.
«Речь в ней идет не о реализации, а об использовании… Можно взять реализацию из Александреску. Книжка его очень умная и толковая. Но вся статья написана о том, как использовать и убрать недостатки, присущие этому паттерну.»
Взять, например, макрос BIND_TO_SELF_SINGLE. Он говорит о том, что синглтон связывается сам с собой. Здесь мне не нужно знать, как этот макрос устроен. Мне нужно знать, что в результате получится. В последствии я могу заменить реализацию макроса (если потребуется), а все пользователи даже и не заметят этого. Таким образом, макросы выступают в роли интерфейса, как это ни странно.