Singleton и Многопоточность

У меня есть следующий класс

class Singleton
{
  private:

    static Singleton *p_inst;
    Singleton();

  public:

    static Singleton * instance()
    {
      if (!p_inst)
      {
        p_inst = new Singleton();
      }

      return p_inst;
    }
};

Уточните меры предосторожности, принятые при реализации Singleton в многопоточной среде.

5
задан CharlesB 10 November 2011 в 09:44
поделиться

5 ответов

В многопоточности этот раздел

if(!p_inst)
{
    p_inst = new Singleton();
}

фактически представляет собой 3 отдельных действия. Вы получаете значение p_inst , устанавливаете значение p_inst и записываете значение p_inst . Таким образом, get-set-write означает, что вам нужно установить блокировку вокруг p_inst , иначе у вас может быть 2 потока, которые создают значение Singleton , которое использует каждый поток.

Вот как вы можете увидеть проблему, предположим, что ваш Синглтон имеет изменяемое поле val :

thread A -> p_inst is NULL
    thread B -> p_inst is NULL
       thread A -> set to Singleton (1)
           thread B -> set to Singleton (2)
              thread C -> p_inst is Singleton (2)
                  thread A -> set val to 4
                      thread B -> set val to 6
                         thread C -> get val (it's 6)
                             thread A -> get val (it's 4!!)

Понимаете? Вокруг плавают 2 копии синглтона, ни одна из которых не знает друг о друге. Третий поток, проверяющий Singleton , увидит только последнее назначение. Но с помощью блокировки вы можете предотвратить множественное присвоение и подобные проблемы.

7
ответ дан 18 December 2019 в 07:08
поделиться

Для многопоточного построения используйте статическую переменную в функции instance (). Инициализация статических переменных автоматически защищена компилятором. Любые другие операции требуют явной блокировки. Используйте мьютексы.

class Singleton
{
  private:

    Singleton();

  public:

    static Singleton * instance()
    {
      static Singleton inst;
      return &inst;
    }
};
1
ответ дан 18 December 2019 в 07:08
поделиться

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

5
ответ дан 18 December 2019 в 07:08
поделиться

Буду краток: это зависит от вашего компилятора.

  • Если ваш компилятор реализует многопоточную синхронизацию для локальной статики (т.е. статических экземпляров, встроенных в метод), то используйте ее и покончите с этим.
  • Если нет, то Херб Саттер доказал, что это невозможно.

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

Есть два способа справиться с этим, которые не требуют осознания многопоточности.

  1. Просто использовать статический экземпляр вместо динамического выделения. Безопасно и просто. Может возникнуть проблема с порядком инициализации, если вам нужно получить доступ к нему из другой static переменной
  2. Создайте экземпляр singleton ДО наличия более чем одного потока. Обычный трюк - вызвать его из main.

Конечно, главный вопрос в том, не можете ли вы просто передать ссылку на объект, а не создавать глобальную переменную? Это бы упростило тестирование ;)

4
ответ дан 18 December 2019 в 07:08
поделиться

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

  • Действительно ли вашему синглтону нужна потокобезопасность?

    Если нет, рассмотрите потоково-статический подход

  • Вы хотите гарантировать, что не будут созданы два экземпляра синглтона?

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

  • Вы хотите гарантировать, что в конечном итоге останется только один экземпляр?

  • Вы заботитесь о затратах на блокировку?

    Если нет (что довольно часто), вы можете просто заблокировать его и быть счастливым.

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

1
ответ дан 18 December 2019 в 07:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: