У меня есть куча потоков. Они должны получить доступ к синглтону, содержащему данные конфигурации, который инициализируется один раз при создании синглтона. Отсюда и первый доступ. Поэтому дальнейшие действия над синглтоном доступны только для чтения. Нужны ли критические разделы в этом случае?
Похоже, потому что данные созданы лениво при первом обращении указатель или ссылка на ваш синглтон будет доступен для чтения и записи. Это означает, что вам нужен критический раздел.
На самом деле, желание избежать критической секции, сохраняя ленивую инициализацию в этой ситуации, было настолько повсеместно сильным, что это привело к созданию двойная проверка блокировки антипаттерна.
С другой стороны, если вы должны были инициализировать свой синглтон с нетерпением перед чтением вы сможете избежать критической секции для доступа к неизменяемому объекту через постоянный указатель / ссылку.
Я понимаю ваш вопрос, так как в вашем синглтоне есть ленивая инициализация. Инициализируется только для первого чтения.
Следующие последовательные чтения являются потокобезопасными. Но как насчет одновременного чтения во время инициализации?
Если у вас есть такая ситуация:
SomeConfig& SomeConfig::getInstance()
{
static SomeConfig instance;
return instance;
}
Тогда это зависит от вашего компилятора. Согласно этому сообщение в C ++ 03 это зависит от реализации, если эта статическая инициализация является поточно-ориентированной.
Для C ++ 11 это потокобезопасно — см. Ответы на это сообщение, цитата:
такая переменная инициализируется при первом прохождении контроля через ее объявление; такая переменная считается инициализированной по завершении ее инициализации. […] Если элемент управления вводит объявление одновременно во время инициализации переменной, параллельное выполнение должно ожидать завершения инициализации.
Стоит отметить, что доступ только для чтения к глобальным переменным является потокобезопасным.
Нет. Если вы просто читаете эти данные после полной инициализации и данные никогда не меняется тогда нет возможности возникновения состояния гонки.
Однако, если данные записываются / изменяются каким-либо образом, вам необходимо синхронизировать доступ к ним, т.е. заблокировать данные перед записью.
Если вы когда-либо читаете только некоторые общие данные и никогда не пишете, вам не нужно синхронизировать доступ.
Синхронизировать нужно только тогда, когда совместно используемый фрагмент данных одновременно читается и записывается.
Официальное правило в спецификации состоит в том, что гонка данных — это когда один поток может одновременно записывать в переменную, а другой поток читает или записывает одну и ту же переменную.
Если вы можете доказать, что инициализация должна произойти до того, как кто-либо из читателей сможет прочитать, синхронизация не требуется. Чаще всего это достигается инициализацией перед созданием (или синхронизацией) потоков или использованием статических переменных хранения, которые C ++ 11 гарантирует некоторую синхронизацию при