Singleton* Singleton::Instance () {
if (_instance == 0) {
_instance = new Singleton;
}
return _instance;
}
Как известно, одновременное чтение и запись одной и той же неатомарной переменной из разных потоков — data race (оно же UB). Что и происходит, если поток 1 записывает _instance (строка 3), а поток 2 читает (строка 2).
Но это еще нормально, ведь это 90-ые годы, тогда еще многопоточки в стандарте не было. Просто не нужно использовать его в многопоточной программе, ну и хотя бы добавить delete _instance.
Мне больше нравится такое написание (код ниже), которое, как ни странно, встречается нередко.
Singleton* Singleton::Instance()
{
if (!instance)
{
std::lock_guard<std::mutex> lock(mutex);
instance = new Singleton;
}
return instance;
}
Что автор хочет этим сказать? Что это можно использовать в многопоточной программе или зачем тогда lock_guard?
Где? В статье не используется mutex вообще. Если речь про комментарий, то там так и написано, что это гонка.
С точки зрения гонки этот код ничем не лучше того, что был в предыдущем комментарии.
Это синглтон.
И в статье как раз сказано, что синглтона из GoF не будет, так как ...
-
Спасибо, исправил.
В книге "Design Patterns" приводиться следующий пример.
Как известно, одновременное чтение и запись одной и той же неатомарной переменной из разных потоков — data race (оно же UB). Что и происходит, если поток 1 записывает _instance (строка 3), а поток 2 читает (строка 2).
Но это еще нормально, ведь это 90-ые годы, тогда еще многопоточки в стандарте не было. Просто не нужно использовать его в многопоточной программе, ну и хотя бы добавить delete _instance.
Мне больше нравится такое написание (код ниже), которое, как ни странно, встречается нередко.
Что автор хочет этим сказать? Что это можно использовать в многопоточной программе или зачем тогда lock_guard?
По факту, здесь тот же data race.