c ++: является ли этот метод getInstance () моим одноэлементным потокобезопасным?

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

                static T& getInstance()
            {
#ifndef STATIC_VARIABLES_ARE_THREADSAFE
                boost::mutex mutex; 
                boost::lock_guard lock(mutex);
#endif
                static T instance;
                return instance;
            }

это потокобезопасный, или я должен использовать boost :: call_once? Придаст ли ускорение мне какое-то преимущество в производительности по сравнению с этим подходом?

РЕДАКТИРОВАТЬ: Хорошо, моя первая идея, очевидно, была неправильной. Чтобы прояснить вопрос. Можно ли безопасно инициализировать boost :: mutex статически? Нравится:

class Singleton
{
private:
static boost::mutex m_mutex;

public:
static Singleton & getInstance()
{
    boost::lock_guard lock(m_mutex);
    static T instance;
    return instance;
}

};

Это рабочий подход или на самом деле статически запускать boost :: mutex небезопасно (это то, что я читал)?

EDIT2: Кстати, это была ссылка http://uint32t.blogspot.com/2007/12/you-lazy-bastard-part-1.html


person moka    schedule 24.05.2011    source источник
comment
Вы проверяли этот вопрос: эффективный потокобезопасный синглтон в C ++ (stackoverflow.com/questions/2576022/)   -  person yasouser    schedule 25.05.2011
comment
да, но мой вопрос скорее в том, можно ли статически инициализировать мьютекс повышения, потому что в этом случае проблема может быть решена довольно легко.   -  person moka    schedule 25.05.2011
comment
Синглтоны - это зло, не используйте их, если вы действительно ... ДЕЙСТВИТЕЛЬНО должны :)   -  person    schedule 25.05.2011


Ответы (4)


Поскольку каждый вход в функцию будет создавать свою собственную блокировку, блокировка будет совершенно бесполезной; любое количество потоков может войти в функцию, заблокировать разные блокировки и одновременно начать возиться со статическими данными.

Вы можете создать блокировку в области видимости файла (или статического класса); это обеспечит его своевременное создание при условии, что вы не запускаете потоки до main(). Однако это также приведет к сериализации записи в функцию даже после инициализации статических данных.

Почему бы просто не определить ваши статические данные в области видимости файла (или статического класса) в первую очередь?

person bdonlan    schedule 24.05.2011
comment
Теперь, когда вы это говорите, это довольно очевидно, спасибо! Думаю, тогда мне нужно пойти по маршруту boost / std :: call_once. Верно ли, что мьютекс повышения не может быть инициализирован статически? - person moka; 25.05.2011
comment
Что ж, можно ли статически инициализировать мьютекс ускорения? Как уже говорилось, я где-то читал, что это не так, поэтому я не уверен, что это правильный подход. см. обновленный пост! - person moka; 25.05.2011
comment
Инициализировать его как статическую переменную области функции небезопасно; это потому, что два потока, входящие в функцию, могут попытаться инициализировать сам мьютекс одновременно. Как статический уровень класса, он безопасен до тех пор, пока вы не получите к нему доступ до завершения статической инициализации (это проблема с любым статическим типом, отличным от POD - см. parashift.com/c ++ - faq-lite / ctors.html # faq-10.14) - person bdonlan; 25.05.2011
comment
@bdonlan: обратите внимание, что, хотя это правильно для C ++ 03, в C ++ 11 статические локальные переменные гарантированно инициализируются средой выполнения в потокобезопасном режиме. - person ildjarn; 25.05.2011
comment
Это, безусловно, вариант. - person bdonlan; 25.05.2011
comment
вот почему я использую проверку #ifndef STATIC_VARIABLES_ARE_THREADSAFE. Сейчас я просто буду использовать статический мьютекс уровня класса, если потоковая инициализация статических переменных не гарантируется, поскольку это кажется достаточно безопасным. - person moka; 25.05.2011

GCC обеспечивает поточно-безопасную инициализацию статических переменных. Итак, если вы используете GCC, вам не нужно заботиться о правильной инициализации статических переменных.

person DimanNe    schedule 25.05.2011

Вам действительно нужно использовать блокировку. Однако схема boost::mutex, которую вы предлагаете, не работает, поскольку вы выделяете мьютекс в стеке, и каждый из нескольких одновременных вызывающих абонентов получит свой собственный мьютекс.

person NPE    schedule 24.05.2011

Попробуйте использовать реализацию Meyers Singleton.

class MySingleton {
public:
  static MySingleton& getInstance() {
    static MySingleton instance;
    return instance;
  }
private:
  MySingleton();
  ~MySingleton();
  MySingleton(const MySingleton&)= delete;
  MySingleton& operator=(const MySingleton&)= delete;

};

MySingleton::MySingleton()= default;
MySingleton::~MySingleton()= default;


// Usage
int main() {
  MySingleton::getInstance();
}

Подробнее…

person danger89    schedule 21.01.2020