Singleton & Multi-Threading -- c++ поле с участием multithreading поле с участием singleton пол Связанный проблема

Singleton & Multi-threading


6
vote

проблема

русский

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

 <код> class Singleton {   private:      static Singleton *p_inst;     Singleton();    public:      static Singleton * instance()     {       if (!p_inst)       {         p_inst = new Singleton();       }        return p_inst;     } };   

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

Английский оригинал

I have the following class

class Singleton {   private:      static Singleton *p_inst;     Singleton();    public:      static Singleton * instance()     {       if (!p_inst)       {         p_inst = new Singleton();       }        return p_inst;     } }; 

Please do elaborate on precautions taken while implementing Singleton in multi-threaded environment .

</div
        
     
     

Список ответов

7
 
vote
vote
Лучший ответ
 

в мульти-резьбе, этот пункт

 <код> if(!p_inst) {     p_inst = new Singleton(); }   

на самом деле 3 отдельных действия. Вы получаете значение p_inst , устанавливая значение p_inst и написание значения <код> p_inst . Таким образом, Get-Set-Write означает, что вам нужно поставить замок <код> p_inst в противном случае, вы можете иметь 2 потока, которые создают значение NSFetchRequest0 значение того, что каждое использует каждая нить.

Вот как вы можете просматривать проблему, предположим, что ваш <код> NSFetchRequest1 имеет смежное поле <код> NSFetchRequest2 :

 <код> NSFetchRequest3  

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

 

In multi-threading that clause

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

is actually 3 separate actions. You are getting the value of p_inst, setting the value of p_inst and writing the value of p_inst. So get-set-write means that you need to put a lock around p_inst otherwise you can have 2 threads which create a Singleton value that each thread uses.

Here is how you can view the issue, assume that your Singleton has a mutable field 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!!) 

You see? There's 2 copies of a Singleton floating about, neither of which knows about the other. The third thread which checks on the Singleton is only going to see the last assignment. But with locking, you can prevent multiple assignment and these types of problems.

</div
 
 
         
         
5
 
vote

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

 

You will have to use a mutex and lock the pointer before assigning or reading it, making this a slow (and imo just plain terrible) design pattern.

</div
 
 
4
 
vote

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

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

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

Есть 2 способа справиться с этим, что не требует какого-либо многопотативного осведомленности.

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

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

 

I will be brief: it depends on your compiler.

  • If your compiler implements multi-threading synchronization for local static (ie static instances embedded in a method), then use it and be done with it.
  • If not, Herb Sutter proved it was impossible.

Now, you have to realize that you may not need this.

There are 2 ways to deal with this, that do not require any multithread awareness.

  1. Simply use a static instance instead of dynamically allocate it. Safe and simple. May cause issue with initialization order if you need to access it from another static variable
  2. Create the singleton instance BEFORE having more than one thread. The usual trick is to call it from main.

Of course, the real question is: can't you just pass a reference to the object rather than creating a global variable ? It would make testing easier ;)

</div
 
 
4
 
vote

Вы можете устранить все вопросы, просто выбирая (любой выбранный вами) такие объекты до начала нескольких потоков. Это не всегда может быть возможным из-за конструктивных ограничений (с использованием синглтонов в статике, вам нужно ленивое распределение и т. Д.), Но это просто и дает вам контроль над последовательностью создания. Иногда отслеживание проблем с учетом порядка и времени выделения таких объектов - это хлопот, которую вы можете легко избежать.

P.S. - Я знаю, что это не отвечает на ваш вопрос, но это может быть практическим решением реальной проблемы без сложности.

 

You can eliminate all issues by simply allocating (any way you choose) such objects before multiple threads are started. This may not always be possible due to design constraints (using the singletons in statics, you NEED lazy allocation, etc.), but it is simple and gives you control of the creation sequence. Sometimes tracking down issues with regard to order and time of allocation of such objects is a hassle that you can easily avoid.

P.S. - I know that this doesn't directly answer your question, but it may be a practical solution to a real problem without complexity.

</div
 
 
1
 
vote

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

 <код> class Singleton {   private:      Singleton();    public:      static Singleton * instance()     {       static Singleton inst;       return &inst;     } };   
 

For multithreaded construction, use static variable in an instance() function. Initialization of static variables is automatically protected by the compiler. Any other operations require explicit locking. Use mutexes.

class Singleton {   private:      Singleton();    public:      static Singleton * instance()     {       static Singleton inst;       return &inst;     } }; 
</div
 
 
     
     
1
 
vote

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

    .
  • Ваш синглтон на самом деле нуждается в безопасности потоков?

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

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

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

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

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

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

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

 

You should ask yourself what you mean by thread safety.

  • Does your singleton actually need thread safety?

    If not, consider a thread-static approach

  • Do you want to guarantee that no two instances of the singleton ever get created?

    If not, your above solution is probably fine, without any locking: you've got a race condition on construction - but you don't care since eventually only one will survive - however, you may have a resource leak unless you're careful, which may or may not be significant. (This is essentially a cache).

  • Do you want to guarantee that eventually only one instance remains?

  • Do you care about locking costs?

    If not (which is quite common), you can just put a lock around it and be happy.

A singleton is a pattern that can address various problems - but what flavor of thread-safety is required has little to do with the singleton pattern itself and everything to do with what you want it for.

</div
 
 
 
 

Связанный проблема

57  Как сделать макрос C ++ вести себя как функция?  ( How do i make a c macro behave like a function ) 
Допустим, по какой-то причине вам нужно написать макрос: <код> MACRO(X,Y) . (давайте предположим, что есть веская причина, по которой вы не можете использова...

1  Почему 64-битное целое расширение C ++ называется «долгим долгом»?  ( Why is the 64bit integer extension of c called long long ) 
В отличие от других типов: «int», "логический", "двойной" и т. Д. И даже таможенные классы, есть только одно слово. Однако только одно слово для их типа тольк...

1  Не можете получить программу Math C ++ для работы [дубликата]  ( Cant get math c program to work ) 
<в сторону CLASS = "S-NEWACTS S-WELTIVE__info JS-Post-New Imide MB16« Роль = «Статус»> Этот вопрос уже есть ответы здесь : ...

0  Libusb_Bulk_Transfer добавляет CRC?  ( Does libusb bulk transfer add crc ) 
Я пишу программу пользовательского интерфейса для устройства USB в C ++, используя Visual Studio 2019. Я использую библиотеку Libusb. Я хочу сделать объемную ...

0  Правильный способ использования вариационного шаблона функции вызова со строковыми аргументами C ++  ( Proper way of using variadic template function call with string arguments c ) 
Здравствуйте, что не то, что я здесь делаю, используя вариадические шаблоны через строку? Как правильно использовать его для достижения заданий ниже? <код> ...

-1  Бросить исключение, когда неправильный тип введен в  ( Throw exception when a wrong type is keyed in ) 
Я должен написать программу C ++, в которой функция состоит в том, чтобы прочитать два номера double Тип чисел из клавиатуры и добавить <код> try BLOCK, чт...

0  Использование аргументов Makefile без Foo =  ( Using makefile arguments without foo ) 
У меня есть makefile, который я использую для компиляции одного файла. Когда мне нужно пройти аргумент, я использую цель = TargetFile. Сценарий принимает ар...

501  Как использовать постоянную PI в C ++  ( How to use the pi constant in c ) 
Я хочу использовать постоянные и тригонометрические функции PI в некоторой программе C ++. Я получаю тригонометрические функции с помощью <код> include <math....

1  Шаблон статических классов через динамические связанные библиотеки  ( Template static classes across dynamic linked libraries ) 
У меня есть классовый класс со статическим значением, как это: <код> template <class TYPE> class A{ static TYPE value; }; в коде dll I назначаю ст...

5  Что такое "для (x: y)"?  ( What is for x y ) 
Итак, я оглянулся на межпубки о нитках, и я пришел в блог / учебную вещь о нитках, но то, что меня смущено, была эта линия, которую он использовал <код> for...

0  Как настроить VS2008 для эффективного развития C ++  ( How to setup vs2008 for efficient c development ) 
Обычно I Программируйте в C #, но были вынуждены выполнять работу в C ++. Похоже, что интеграция с Visual Studio (2008) действительно плохо по сравнению с C #...

2  Создание хеша для данных больше, чем память (без зарядки)  ( Generating a hash for data larger than memory without getting arrested ) 
Добрый послеобеденный переполнец! ;) Что я хочу сделать: Я заинтересован в проверке передаваемой целостности файлов. Как я подошел к нему: Я рассм...

-1  Неожиданный идентификатор ошибки - не уверен, почему (C ++)  ( Unexpected error id not sure why c ) 
IM Реализация программы C ++, по соображениям проекта оно должно быть включено в один файл, поэтому я не могу поставить то, что вы обычно в отдельном файле за...

0  Ошибка: аргумент типа "void (opca_hello ::) ()" не соответствует "void * (*) (void *)"  ( Error argument of type void opca hello does not match void void ) 
Я написал очень простой код для резьбы. Поскольку я очень новый для этого, я понятия не имею об ошибке. <код> class opca_hello { public: void hello(); } v...

0  Проблема дизайна - создание шрифта Global (C ++, Marmalade)  ( Design issue making a font global c marmalade ) 
У меня есть проект Marmalade C ++, где встроенный в шрифте не масштабируется на экран. Чтобы справиться с этим вопросом, я делаю пользовательский шрифт, котор...

Связанный проблема

57  Как сделать макрос C ++ вести себя как функция? 
1  Почему 64-битное целое расширение C ++ называется «долгим долгом»? 
1  Не можете получить программу Math C ++ для работы [дубликата] 
0  Libusb_Bulk_Transfer добавляет CRC? 
0  Правильный способ использования вариационного шаблона функции вызова со строковыми аргументами C ++ 
-1  Бросить исключение, когда неправильный тип введен в 
0  Использование аргументов Makefile без Foo = 
501  Как использовать постоянную PI в C ++ 
1  Шаблон статических классов через динамические связанные библиотеки 
5  Что такое "для (x: y)"? 
0  Как настроить VS2008 для эффективного развития C ++ 
2  Создание хеша для данных больше, чем память (без зарядки) 
-1  Неожиданный идентификатор ошибки - не уверен, почему (C ++) 
0  Ошибка: аргумент типа "void (opca_hello ::) ()" не соответствует "void * (*) (void *)" 
0  Проблема дизайна - создание шрифта Global (C ++, Marmalade)