С++ на синглтоне

У меня есть одноэлементный класс, и я уверен, что первый вызов синглтона выполняется только одним потоком. Я реализовал синглтон с ленивой инициализацией.

class MySingleton : private boost::noncopyable {
public:

    /** singleton access. */
    static MySingleton & instance()
    {
        static MySingleton myInstance;
        return myInstance;
    }

    void f1();
    void f2();
    void f3();
    void f4();

private:

    MySingleton();

};

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

Первый вопрос

Такой подход приемлем?

Второй вопрос

У меня есть сложный класс, который должен быть потокобезопасным.
Этот класс должен быть одноэлементным. Как можно, чтобы вызов различных методов класса был потокобезопасным. Например.

{ 
    MySingletonLock lock;
    // Other thread must wait here.
    MySingleton::instance().f1();
    MySingleton::instance().f3();
}

Как я могу получить это?


person Elvis Dukaj    schedule 20.05.2013    source источник
comment
почему у вас есть фабрика, которая создает синглтоны? звучит очень туманно.   -  person Dory Zidon    schedule 20.05.2013
comment
Синглтон никогда не бывает приемлемым. Не используйте Singleton, это ужасный, ужасный паттерн. Кроме того, вам не удалось предотвратить один экземпляр, ваш класс имеет общедоступный конструктор по умолчанию, поэтому любой может создать больше экземпляров. Без предотвращения нескольких экземпляров все, что у вас есть, — это шаблон GlobalState, который является полным отстоем. Сделайте себе одолжение и измените свой дизайн прямо сейчас.   -  person Jonathan Wakely    schedule 20.05.2013
comment
Верно, что Джонатан... это похоже на то, что у вас есть классы и экземпляры, но давайте также создадим глобальный. плюс singleton очень безопасен для UNThread!   -  person Dory Zidon    schedule 20.05.2013
comment
Кроме того, определите потокобезопасность. Безопасно в каком смысле? Для каких моделей использования? Защищен от случайного неправильного использования? Безопасен от решительных злонамеренных идиотов?   -  person Jonathan Wakely    schedule 20.05.2013
comment
Конструктор класса является закрытым и реализуется в другом месте. У меня есть возможность использовать синглтон, потому что класс используется во многих частях фреймворка. Синглтон кажется мне подходящим для этой цели...   -  person Elvis Dukaj    schedule 20.05.2013
comment
Извините, но я очень хорошо разбираюсь в многопоточности... Я знаю только одну скороговорку: потребитель-производитель-очередь. Это единственный шаблон, который я использую для синхронизации потоков.   -  person Elvis Dukaj    schedule 20.05.2013
comment
P.S.: У меня есть мастер-класс по инициализации библиотеки. Здесь, во-первых, когда запускаются все потоки, я вызываю SINGLETON::insance(), чтобы убедиться, что у меня есть только один экземпляр для синглтона.   -  person Elvis Dukaj    schedule 20.05.2013
comment
Как-то связанный вопрос: что, если я хочу, чтобы какой-то объект в моем приложении был создан только один раз и живет в течение всего времени жизни приложения? Что я могу использовать вместо синглтона?   -  person maverik    schedule 20.05.2013
comment
Если бы у вас был один синглтон, это, может быть, и хорошо, но много их — это черепок. Кроме того, сложный класс почти по определению не является потокобезопасным — make прост.   -  person Bull    schedule 20.05.2013
comment
Элвис, это противоречит цели «ленивой инициализации». @maverik, во всем мире ни в коем случае не принято, что «одиночки - зло». В качестве альтернативы у вас может быть пространство имен с функциями, а в реализации — статические глобальные переменные (видимые только в этой единице перевода); функции будут интерфейсом для этих переменных.   -  person Rollie    schedule 20.05.2013
comment
@maverick - создай один раз, готово. std::cout не является синглтоном.   -  person Bull    schedule 20.05.2013
comment
В моем программном обеспечении очень мало синглетонов. Они должны быть синглтонами. Мне не очень нравится узор... но для моих целей он хорош.   -  person Elvis Dukaj    schedule 20.05.2013
comment
@elvis.dukaj: Вы признали, что ваш опыт работы с многопоточностью ограничен. Я хотел бы предложить вам прислушаться к совету тех, кто хорошо разбирается в многопоточности, когда они говорят вам, что синглтоны создают больше проблем, чем решают.   -  person John Dibling    schedule 20.05.2013
comment
Хорошо... Если я не могу использовать синглтон... Если у меня есть класс, который: должен использоваться из других классов и должен быть уникальным (например, потому что он взаимодействует с устройством), что мне делать?   -  person Elvis Dukaj    schedule 20.05.2013
comment
@elvis.dukaj: Использование одного класса из другого — это просто. Вы уже знаете, как это сделать. Что касается уникальности объекта, моя философия проста: если вам нужен только один экземпляр класса, создайте только один! Передавайте общие (умные) указатели или предоставляйте доступ через какой-либо брокерский механизм.   -  person John Dibling    schedule 20.05.2013
comment
Кто-то предлагает не использовать синглтоны... просто иметь глобальную статическую переменную (например, std::cout). Но что, если конструктор класса может бросить? приложение не может запуститься, и это неприемлемо для моего программного обеспечения.   -  person Elvis Dukaj    schedule 21.05.2013


Ответы (1)


Ответ на ваш второй вопрос:

class MyProtectedSingleton: public MySingleton
{
public:
   void f1()
   {
       MySingletonLock lock;
            // Other thread must wait here.
       MySingleton::instance().f1();    
   }

  void f2()
  {
      MySingletonLock lock;
        // Other thread must wait here.
      MySingleton::instance().f2();    
  }
};

Вызовите f1, f2 и т. д. через обертки в MyProtectedSingleton.

person Liviu    schedule 20.05.2013
comment
Это защищает только вызов f1()... Я хочу, чтобы вызов f1() f2()... был атомарным - person Elvis Dukaj; 20.05.2013
comment
Теперь у вас есть защита f2 :D Сколько у вас может быть функций? И это почти бесплатно с силой встроенного. - person Liviu; 20.05.2013
comment
(незначительное) Вы написали приемлемо, но я не могу отредактировать ваш вопрос из-за такой маленькой ошибки. - person Liviu; 20.05.2013
comment
но из вызова f1 и вызова f2 другой поток может вызвать f1. - person Elvis Dukaj; 20.05.2013
comment
Обратите внимание, что объект блокировки, используемый для защиты f1, f2 и т. д., должен быть членом класса singleton, если вы говорите, что «поток не может выполнить f1, пока выполняется f2». Менее ограничительным вариантом было бы иметь один объект блокировки для каждой функции, который может быть статической локальной переменной при использовании С++ 11 (я думаю, VS2012 и g++ 4.7), поскольку стандарт теперь гарантирует, что статические локальные переменные полностью инициализированы, прежде чем они смогут использоваться. - person Rollie; 20.05.2013
comment
Вы можете сделать f1, f2 и т. д. protected в MySingleton. И блокировка может быть пустой (ничего не делать) для однопоточной ситуации. - person Liviu; 20.05.2013