Re[5]: thread safe singlton - возможно ли такое в принципе
От: Lexey Россия  
Дата: 12.07.04 14:16
Оценка:
Здравствуйте, Lexey, Вы писали:

L>Здравствуйте, WolfHound, Вы писали:


L>>>Тут недавно в boost.develop появилась забавная нитка, в которой один перец довольно убедительно утверждает, что спин-локи, вообще говоря, довольно хреновая вещь, если у них нет fallback'а на синхронизационные примитивы ОС (там шла дискуссия по поводу boost::lightweight_mutex).

WH>>А можно ее сюда процитировать?

L>Если только в понедельник. Дома я ее не читаю, а подписываться ради этого лень.


Ну держись, сейчас буду постить.

I believe there is a mistake in the 'details/lwm_gcc.hpp' and 
'details/lwm_linux.hpp' (and possibly the other lightweight_mutex 
implementation as well -- I haven't looked at them).
 
In both of these files we have a counter (m_.a_) that is initialized to 1.  
The lock routine is implemented as follows:
 
while( !__exchange_and_add(&m_.a_, -1) ){
  __atomic_add(&m_.a_, 1);
  sched_yield();
}
 
The unlock as:
__atomic_add(&m_.a_, 1);
 
This works if there are only two contenders for the lock.  It can fail if 
there are three or more:
 
1-  Thread one takes the lock, putting the counter at 0.
2-  Thread two does the __exchange_and_add, fails the test, and then its time 
time slice expires before the __atomic_add, leaving the counter at -1.
3-  Thread three also takes the lock (because !-1 is false).
 
A simple solution is to initialize the counter to zero and replace the above 
lock by:
 
while( __exchange_and_add(&m_.a_, 1) ){
  __atomic_add(&m_.a_, -1);
  sched_yield();
}
 
and the unlock by:
__atomic_add(&m_.a_, -1);
 
This would result in:
1-  Thread one takes the lock, putting the counter at 1.
2-  Thread two does the __exchange_and_add, fails the test, and then its time 
slice expires before it can do the __atomic_add, leaving the counter at 2.
3-  Thread cannot take the the lock (because 2 is true).
 
- -T
 
- -- 
 Tyson Whitehead  (-twhitehe@uwo.ca -- WSC-)
 Computer Engineer                        Dept. of Applied Mathematics,
 Graduate Student- Applied Mathematics    University of Western Ontario,
 GnuPG Key ID# 0x8A2AB5D8                 London, Ontario, Canada


---------------------------------------------------------------------------------------------------------------------

Tyson Whitehead wrote:
>  I believe there is a mistake in the 'details/lwm_gcc.hpp' and 
'details/lwm_linux.hpp' (and possibly the other lightweight_mutex 
implementation as well -- I haven't looked at them). 

 
I am not sure what the status of these are.  Are other components
supposed to be using these?  In addition to what you mentioned, they're
broken in other ways:
 
>  In both of these files we have a counter (m_.a_) that is initialized to 1.  
The lock routine is implemented as follows:
while( !__exchange_and_add(&m_.a_, -1) ){
  __atomic_add(&m_.a_, 1);
  sched_yield(); 

 
If a low priority thread is preempted by a high priority thread
immediately before __atomic_add, and the high priority thread is
attempting to grab the spinlock, deadlock is acheived, despite the
sched_yield().
 
I think that spinlocks should not be used in a way other than as an
optimization for the non-contended case in an algorithm with fallback to
a real synchronization primative.  I think it is a bug to do otherwise
on most non-realtime systems.
 
Aaron W. LaFramboise

-------------------------------------------------------------------------------------------------------------------------

Aaron W. LaFramboise wrote:
>  I am not sure what the status of these are.  Are other components
supposed to be using these? 

 
I came upon them when I was checking out the smart pointers implementation.  
Grepping the source seems to indicate 'lightweight_mutex.hpp' is only used by  
the smart pointers (only included by 'quick_allocator.hpp' and 
'shared_count.hpp') under multithreaded conditions.
 
>  In addition to what you mentioned, they're broken in other ways: 
If a low priority thread is preempted by a high priority thread
immediately before __atomic_add, and the high priority thread is
attempting to grab the spinlock, deadlock is acheived, despite the
sched_yield(). 

 
I missed that one.  You're right though, and not only that, but the 
sched_yield manpage states (I'm assuming this applies to threads -- threads 
in Linux are actually processes -- right?):
 
"Note: If the current process is the only process in the highest priority list 
at that time, this process will continue to run after a  call to 
sched_yield."
 
The implementer seemed to be aware there could be priority problems though.  
The relevant comments in 'lightweight_mutex.hpp' are:
 
//  * Used by the smart pointer library
//  * Performance oriented
//  * Header-only implementation
//  * Small memory footprint
//  * Not a general purpose mutex, use boost::mutex, CRITICAL_SECTION or
//    pthread_mutex instead.
//  * Never spin in a tight lock/do-something/unlock loop, since
//    lightweight_mutex does not guarantee fairness.
//  * Never keep a lightweight_mutex locked for long periods.
//
//  The current implementation can use a pthread_mutex, a CRITICAL_SECTION,
//  or a platform-specific spinlock.
//
//  You can force a particular implementation by defining
//  BOOST_LWM_USE_PTHREADS,
//  BOOST_LWM_USE_CRITICAL_SECTION, or 
//  BOOST_LWM_USE_SPINLOCK.
//
//  If neither macro has been defined, the default is to use a spinlock on
//  Win32, and a pthread_mutex otherwise.
//
//  Note that a spinlock is not a general synchronization primitive. In
//  particular, it is not guaranteed to be a memory barrier, and it is
//  possible to "livelock" if a lower-priority thread has acquired the
//  spinlock but a higher-priority thread is spinning trying to acquire the
//  same lock.
//
//  For these reasons, spinlocks have been disabled by default except on
//  Windows, where a spinlock can be several orders of magnitude faster than a
//  CRITICAL_SECTION.
 
The current Win32 doesn't have the counter problems, and claims to be able to 
yield to lower priority threads, so it should be okay.  The relevant lock 
routine is (m_.l_ is initialized to 0):
 
while( InterlockedExchange(&m_.l_, 1) ){
  // Note: changed to Sleep(1) from Sleep(0).
  // According to MSDN, Sleep(0) will never yield
  // to a lower-priority thread, whereas Sleep(1)
  // will. Performance seems not to be affected.
  Sleep(1);
}
 
The unlock routine is:
InterlockedExchange(&m_.l_, 0);
 
- -T
 
- -- 
 Tyson Whitehead  (-twhitehe@uwo.ca -- WSC-)
 Computer Engineer                        Dept. of Applied Mathematics,
 Graduate Student- Applied Mathematics    University of Western Ontario,
 GnuPG Key ID# 0x8A2AB5D8                 London, Ontario, Canada

-------------------------------------------------------------------------------------------

Tyson Whitehead wrote:
>  The current Win32 doesn't have the counter problems, and claims to be able to 
yield to lower priority threads, so it should be okay.  The relevant lock 
routine is (m_.l_ is initialized to 0):
while( InterlockedExchange(&m_.l_, 1) ){
  // Note: changed to Sleep(1) from Sleep(0).
  // According to MSDN, Sleep(0) will never yield
  // to a lower-priority thread, whereas Sleep(1)
  // will. Performance seems not to be affected.
  Sleep(1);
} 

 
For what its worth, while it avoids deadlocking problems, this code is
also wrong.
 
Synchronization code should never sleep.  That code above will actually
sleep for the minimum amount of time Windows allows, which is usually
10ms.  I measured the performance of this spinlock a while back when
improvements to GCC's Windows mutexes were being discussed on the MinGW
lists, and in some cases where there is substanctial contention over
short-lived locks, the performance degradation is quite unacceptable.
Certain naïve benchmarks might not notice, though, because during the
period waiters are sleeping, the lock will be accessable.
 
I think the code above could lead to severe slowdowns in some usage
cases, and could lead to difficult to diagnose intermittant 'blips' of
bad performance in others.
 
In any case, my point is that spinlocks are always going to be wrong in
these sorts of situations unless coupled with some other primative.  In
fact, spinning at all is usually the wrong thing to do.  On single CPU
systems, it is always a waste of precious time.  On multi CPU systems,
it can cause very undesirable memory bus slowdowns.
 
The best general locking strategy I have seen--which is used by Linux
futexes and GCC for Windows' new locks--is where a normal scheduler
locking primative is wrapped by a quick userspace atomic operation to
avoid locking in the noncontended case.  The downside is that, on
Windows for example, this will require 8 bytes of storage.  I'm not sure
how shared_ptr uses mutexes, but this might not be acceptable.
 
These spinlocks need to be fixed.  Is anyone working on this?
 
Aaron W. LaFramboise
-------------------------------------------------------------------------------------

Aaron,
 
Before taking your word for it, I would like to hear more about how your
benchmarks relate to smart pointers.
 
It sounds reasonable that the kind of lock described will perform badly in
high-contention situations. But what evidence do you have that there is any
probability of high contention, especially when, as you say, the locks are
short-lived? These locks aren't taken every time the smart pointer is accessed;
they're only taken when a copy is made. So to get the high contention you speak
of, you would have to have two threads repeatedly making copies of the "same"
smart pointer. From where I stand, this seems sufficiently rare that the extra
performance gain in the common cases is worth it.
 
/Mattias
-------------------------------------------------------------------------------------

flodin@cs.umu.se wrote:
>  It sounds reasonable that the kind of lock described will perform badly in
high-contention situations. But what evidence do you have that there is any
probability of high contention, especially when, as you say, the locks are
short-lived? These locks aren't taken every time the smart pointer is accessed;
they're only taken when a copy is made. So to get the high contention you speak
of, you would have to have two threads repeatedly making copies of the "same"
smart pointer. From where I stand, this seems sufficiently rare that the extra
performance gain in the common cases is worth it. 

 
[these comments are specific to the win32 spinlock discussed]
 
I have two specific concerns.
 
1) Personally, I value predictable performance.  I would prefer slight
performance degradation (Note, however, that I am not examining the
actual numbers.) to the case where I may have an occasional very long
wait.  (Specific example: If a graphically intensive program is aiming
for 30 frames per second, that is only about 30ms per frame.  It would
be very unfortunate if, even occasionally, a single smart pointer copy
accounted for 1/3 of the time it took to render a frame.)
 
2) In "thundering herd" situations, contention is unavoidable, and
performance may be paramount.  The possibility of a single thread
halting many other threads for 10ms on a machine with many processors is
disturbing. (Specific example: In a case where thread is producing work
for many consumer threads on a multiprocessor machine, and obtaining the
work involves copying a smart pointer, it is possible that some amount
of threads will forced to sleep every single time, which might be a
substantial percentage of total job wall clock time.)
 
In any case, I feel fairly strongly that sleeping is not the right thing
to do.  Despite the weakness in appeal to authority, I will note that I
have seen Butenhof make the same assertion on Usenet, surely in a manner
more eloquent than mine.
 
I previously neglected to suggest alternatives.
 
1) A generally sound 8-byte mutex could be used.  I am not sure how bad
this would be in terms of storage efficiency.  It may be possible to
implement it using less storage, but I have no specific information on this.
 
2) I've seen a shared_ptr count implementation that used
InterlockedIncrement instead of the lwm code.  I have not examined this
in detail; however it seems that an approach like this is better in all
respects than trying to manage locks if the only need is to maintain a
count (which is what many mutex primatives are doing anyway).  Is there
some reason this cannot be used?
 
What do you think?
 
Aaron W. LaFramboise
--------------------------------------------------------------------------------



и т.д. Как потом выяснилось, насчет 10 ms, он все-таки загнул. Но народ вроде сошелся на том, что критичексая секция все-таки получше будет.
"Будь достоин победы" (c) 8th Wizard's rule.
Re[6]: thread safe singlton - возможно ли такое в принципе
От: Andrew S Россия http://alchemy-lab.com
Дата: 12.07.04 15:01
Оценка:
L>и т.д. Как потом выяснилось, насчет 10 ms, он все-таки загнул. Но народ вроде сошелся на том, что критичексая секция все-таки получше будет.
Естественно, любой практически системный сервис, предоставляемый OS будет лучше (ну или _должен_ быть лучше). Но..
Каким образом Вы сможете использовать критическую секцию в приведенном синглетоне? Ее надо сначала проинициализировать — pkunzip.zip получается. Это во-первых. А во-вторых — производительность auto_lock нас не волнует, поскольку используется двойная проверка с memory barrier — т.о. в блок с auto_lock мы будем попадать только на этапе инициализации объекта синглтона, да и то скорее всего один раз. Единственная альтернатива (критические секции и неименованные мутексы не подойдут по приведенным выше соображениям) — это именованый мутекс. Но я сильно сомневаюсь, что поиск объекта по имени работает достаточно быстро (настолько быстро, чтобы быть существенно быстрее представленной реализации). В общем, в данном применении это наиболее оптимальный вариант lightweight мутекса, наверное. К тому же не засоряется пространство имен объектов.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[7]: thread safe singlton - возможно ли такое в принципе
От: Lexey Россия  
Дата: 12.07.04 20:31
Оценка:
Здравствуйте, Andrew S, Вы писали:

L>>и т.д. Как потом выяснилось, насчет 10 ms, он все-таки загнул. Но народ вроде сошелся на том, что критичексая секция все-таки получше будет.

AS>Естественно, любой практически системный сервис, предоставляемый OS будет лучше (ну или _должен_ быть лучше). Но..
AS>Каким образом Вы сможете использовать критическую секцию в приведенном синглетоне? Ее надо сначала проинициализировать — pkunzip.zip получается. Это
AS> во-первых. А во-вторых — производительность auto_lock нас не волнует, поскольку используется двойная проверка с memory barrier — т.о. в блок с auto_lock мы будем попадать только на этапе инициализации объекта синглтона, да и то скорее всего один раз. Единственная альтернатива (критические секции и неименованные мутексы не подойдут по приведенным выше соображениям) — это именованый мутекс. Но я сильно сомневаюсь, что поиск объекта по имени работает достаточно быстро (настолько быстро, чтобы быть существенно быстрее представленной реализации). В общем, в данном применении это наиболее оптимальный вариант lightweight мутекса, наверное. К тому же не засоряется пространство имен объектов.

В общем, я это и так знаю. И именованный мьютекс будет в подавляющем числе случаев будет существенно медленнее spin lock'a. Но, речь о том, что наверное самым правльным решением тут будет сочетание обоих приемов — spin lock с ограничением числа прокруток и без sleep'а + именованный мьютекс.
... << RSDN@Home 1.1.4 beta 1 >>
"Будь достоин победы" (c) 8th Wizard's rule.
Re[8]: thread safe singlton - возможно ли такое в принципе
От: WolfHound  
Дата: 13.07.04 08:41
Оценка:
Здравствуйте, Lexey, Вы писали:

L>В общем, я это и так знаю. И именованный мьютекс будет в подавляющем числе случаев будет существенно медленнее spin lock'a. Но, речь о том, что наверное самым правльным решением тут будет сочетание обоих приемов — spin lock с ограничением числа прокруток и без sleep'а + именованный мьютекс.

А в чем понт в спинлоке без слипа на однопроцессорной машине?
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: thread safe singlton - возможно ли такое в принципе
От: Lexey Россия  
Дата: 13.07.04 21:21
Оценка:
Здравствуйте, WolfHound, Вы писали:

L>>В общем, я это и так знаю. И именованный мьютекс будет в подавляющем числе случаев будет существенно медленнее spin lock'a. Но, речь о том, что наверное самым правльным решением тут будет сочетание обоих приемов — spin lock с ограничением числа прокруток и без sleep'а + именованный мьютекс.

WH> А в чем понт в спинлоке без слипа на однопроцессорной машине?

Хм, а в чем понт слипа на однопроцессорной машине? Я вот не могу себе представить, зачем он в этом случае может быть нужен. Если происходит context switch, а lock все еще не отпущен другим потоком, то какой смысл делать слип, если можно сразу делать kernel wait? По хорошему, на однопроцессорной машине спин-лок вообще не нужен (критическая секция, кстати, его и игнорирует на однопроцессорных машинах).
... << RSDN@Home 1.1.4 beta 1 >>
"Будь достоин победы" (c) 8th Wizard's rule.
Re[10]: thread safe singlton - возможно ли такое в принципе
От: WolfHound  
Дата: 14.07.04 05:18
Оценка:
Здравствуйте, Lexey, Вы писали:

L>Хм, а в чем понт слипа на однопроцессорной машине? Я вот не могу себе представить, зачем он в этом случае может быть нужен. Если происходит context switch, а lock все еще не отпущен другим потоком, то какой смысл делать слип, если можно сразу делать kernel wait? По хорошему, на однопроцессорной машине спин-лок вообще не нужен (критическая секция, кстати, его и игнорирует на однопроцессорных машинах).

Быть может я чего не понимаю но если будет так:
поток 1 начал создавать объект и случилось переключение контекста
поток 2 захотел получить доступ к объекту но объект все еще залочен в этом случае Sleep форсирует переключение контекста
или я чего не понял?
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: thread safe singlton - возможно ли такое в принципе
От: Lexey Россия  
Дата: 14.07.04 20:03
Оценка:
Здравствуйте, WolfHound, Вы писали:

L>>Хм, а в чем понт слипа на однопроцессорной машине? Я вот не могу себе представить, зачем он в этом случае может быть нужен. Если происходит context switch, а lock все еще не отпущен другим потоком, то какой смысл делать слип, если можно сразу делать kernel wait? По хорошему, на однопроцессорной машине спин-лок вообще не нужен (критическая секция, кстати, его и игнорирует на однопроцессорных машинах).

WH>Быть может я чего не понимаю но если будет так:
WH>поток 1 начал создавать объект и случилось переключение контекста
WH>поток 2 захотел получить доступ к объекту но объект все еще залочен в этом случае Sleep форсирует переключение контекста
WH>или я чего не понял?

Все так, только какой смысл тут делать sleep, если можно сразу в kernel wait уйти.
... << RSDN@Home 1.1.4 beta 1 >>
"Будь достоин победы" (c) 8th Wizard's rule.
Re[12]: thread safe singlton - возможно ли такое в принципе
От: Andrew S Россия http://alchemy-lab.com
Дата: 14.07.04 20:08
Оценка:
L>Все так, только какой смысл тут делать sleep, если можно сразу в kernel wait уйти.
Пример кода приведите, который в kernel wait уходит?

Вам тут надо переключить конекст (т.е. усыпить тред до следующего shedule) — в виндовс это делается при помощи Sleep.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[13]: thread safe singlton - возможно ли такое в принципе
От: Lexey Россия  
Дата: 15.07.04 20:42
Оценка:
Здравствуйте, Andrew S, Вы писали:

L>>Все так, только какой смысл тут делать sleep, если можно сразу в kernel wait уйти.

AS>Пример кода приведите, который в kernel wait уходит?

Создание именованного ивента + Wait на нем.

AS>Вам тут надо переключить конекст (т.е. усыпить тред до следующего shedule) — в виндовс это делается при помощи Sleep.


Wait как раз и вызовет переключение контекста.
... << RSDN@Home 1.1.4 beta 1 >>
"Будь достоин победы" (c) 8th Wizard's rule.
Re[14]: thread safe singlton - возможно ли такое в принципе
От: Andrew S Россия http://alchemy-lab.com
Дата: 15.07.04 22:16
Оценка:
L>>>Все так, только какой смысл тут делать sleep, если можно сразу в kernel wait уйти.
AS>>Пример кода приведите, который в kernel wait уходит?

L>Создание именованного ивента + Wait на нем.


Вообще то тут мы от этого пытаемся избавиться Посмотрите внимательно код синлтона с двойной проверкой. Сначала идет "грубая" быстрая проверка, просто на interlocked. Далее может идти все что угодно, что обеспечит мемори барриер до и после конструирования объекта и серийность входа.

AS>>Вам тут надо переключить конекст (т.е. усыпить тред до следующего shedule) — в виндовс это делается при помощи Sleep.


L>Wait как раз и вызовет переключение контекста.


Sleep(1) тоже. А если слипа не будет — то тред, попавший в цикл по interlocked, не будет отдавать время и соотв, будет потреблять все процессорное время. Думаю, пользователям (да и инициализирующемуся в это время объекту синглтона) это не очень понравится А особенно не понравится тем, кто будет выполнять сей код на win98, где тред, крутящийся в таком цикле, очень хорошо затормозит систему и растянет процесс инициализации объекта синглтона в другом треде на ооооочень продолжительное время.

И, еще раз — приведенный код (с auto_lock) будет вызываться от силы раз-два, и то при первом обращении к синглтону. Смысл создавать именованый kernel объект и засорять тем самым пространство имен? В общем, повторюсь, предложенный вариант будет вполне корректно работать на win32 (и, вероятно, с yield вместо sleep на linux — тут я не уверен, и прочитка топика, который привели вы, выяснила только одну проблему — что в линксовской используется счетчик (__atomic_add), а не просто обмен значениями, как в реализации, приведенной для win32 WolfHound'ом. Но это уже проблемы ДНК тех, кто писал эту реализацию, по моему глубокому убеждению. I love gnu libs code
В общем — главный плюс этого кода не то, что он быстрее или медленнее нативных именованых объектов, предоставляемых ОС, а то, что он их собственно не требует, позволяя не засорять пространство имен на одноразовое фактически использование.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[15]: thread safe singlton - возможно ли такое в принципе
От: Lexey Россия  
Дата: 17.07.04 18:28
Оценка:
Здравствуйте, Andrew S, Вы писали:

L>>>>Все так, только какой смысл тут делать sleep, если можно сразу в kernel wait уйти.

AS>>>Пример кода приведите, который в kernel wait уходит?

L>>Создание именованного ивента + Wait на нем.


AS>Вообще то тут мы от этого пытаемся избавиться Посмотрите внимательно код синлтона с двойной проверкой. Сначала идет "грубая" быстрая проверка, просто на


Я его в общем-то вполне нормально смотрел.

AS> interlocked. Далее может идти все что угодно, что обеспечит мемори барриер до и после конструирования объекта и серийность входа.


А я и не предлагаю убирать interlock и двойную, я предлагаю заменить спин-лок на kernel wait.

AS>>>Вам тут надо переключить конекст (т.е. усыпить тред до следующего shedule) — в виндовс это делается при помощи Sleep.


L>>Wait как раз и вызовет переключение контекста.


AS>Sleep(1) тоже. А если слипа не будет — то тред, попавший в цикл по interlocked, не будет отдавать время и соотв, будет потреблять все процессорное время. Думаю, пользователям (да и инициализирующемуся в это время объекту синглтона) это не очень понравится А особенно не понравится тем, кто будет выполнять сей код на win98, где тред, крутящийся в таком цикле, очень хорошо затормозит систему и растянет процесс инициализации объекта синглтона в другом треде на ооооочень продолжительное время.


А я где-то предполагал другое?

AS>И, еще раз — приведенный код (с auto_lock) будет вызываться от силы раз-два, и то при первом обращении к синглтону. Смысл создавать именованый kernel объект и


Далеко не факт. Если синглтон долго инициализируется, то вызываться он может много раз.

AS> засорять тем самым пространство имен? В общем, повторюсь, предложенный вариант


Ты боишься засорить пространство имен одним именованным ивентом? Это как-то совсем несерьезно звучит.

AS> будет вполне корректно работать на win32 (и, вероятно, с yield вместо sleep на linux — тут я не уверен, и прочитка топика, который привели вы, выяснила только одну проблему — что в линксовской используется счетчик (__atomic_add), а не просто обмен значениями, как в реализации, приведенной для win32 WolfHound'ом. Но это уже проблемы ДНК тех, кто писал эту реализацию, по моему глубокому убеждению. I love


В таком случае проблемы в ДНК есть у всех программистов.

AS> gnu libs code


В общем-то, этот топик кроме всего прочего обсуждал как раз вредность чистых спин-локов. Именно эту идею я и пытаюсь отстаивать. Кстати, я не привел конец этой дискуссии, так вот там народ сошелся на том, что lightweight_mutex пригоден только для очень коротких операций. В остальных случаях его лучше не использовать. Ты можешь гарантировать, что инициализация синглетона — быстрый процесс?

AS> В общем — главный плюс этого кода не то, что он быстрее или медленнее нативных именованых объектов, предоставляемых ОС, а то, что он их собственно не требует, позволяя не засорять пространство имен на одноразовое фактически использование.


Это как раз совершенно не серьезное преимущество.
В общем, я могу предложить вариант, который наверное устроит и тебя и меня.
Сделать синглетон-критическую секцию, создание которой защитить lightweight_mutex'ом (создание тут быстрое, так что можно). И вот эту критическую секцию и использовать при инициализации остальных синглетонов.
... << RSDN@Home 1.1.4 beta 1 >>
"Будь достоин победы" (c) 8th Wizard's rule.
Re[16]: thread safe singlton - возможно ли такое в принципе
От: Andrew S Россия http://alchemy-lab.com
Дата: 19.07.04 08:38
Оценка:
L>Это как раз совершенно не серьезное преимущество.
L>В общем, я могу предложить вариант, который наверное устроит и тебя и меня.
L>Сделать синглетон-критическую секцию, создание которой защитить lightweight_mutex'ом (создание тут быстрое, так что можно). И вот эту критическую секцию и использовать при инициализации остальных синглетонов.

Одну критическую секция на все? Несерьезно, тормоза будут дикие, более того может быть так, что создание одного синглтона зависит от другого, и это происходит в разных потоках. Придется все-равно по одному именованному объекту на синглтон. Мне кажется, это не очень хорошая мысль. А точнее, очень _не_ хорошая. Впрочем, каждому свое
В любом случае, серебряной пули не существует...
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[17]: thread safe singlton - возможно ли такое в принципе
От: Lexey Россия  
Дата: 19.07.04 20:05
Оценка: +1
Здравствуйте, Andrew S, Вы писали:

L>>Это как раз совершенно не серьезное преимущество.

L>>В общем, я могу предложить вариант, который наверное устроит и тебя и меня.
L>>Сделать синглетон-критическую секцию, создание которой защитить lightweight_mutex'ом (создание тут быстрое, так что можно). И вот эту критическую секцию и использовать при инициализации остальных синглетонов.

AS>Одну критическую секция на все? Несерьезно, тормоза будут дикие, более того может


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

AS> быть так, что создание одного синглтона зависит от другого, и это происходит в разных потоках. Придется все-равно по одному именованному объекту на синглтон. Мне кажется, это не очень хорошая мысль. А точнее, очень _не_ хорошая. Впрочем, каждому


А где ты в критической секции увидел именованные объекты?

AS> свое

AS>В любом случае, серебряной пули не существует...

Это верно.
... << RSDN@Home 1.1.4 beta 1 >>
"Будь достоин победы" (c) 8th Wizard's rule.
Re[18]: thread safe singlton - возможно ли такое в принципе
От: WolfHound  
Дата: 21.07.04 18:50
Оценка:
Здравствуйте, Lexey, Вы писали:

AS>>Одну критическую секция на все? Несерьезно, тормоза будут дикие, более того может

L>Совсем не обязательно. Можно, например, сделать шаблонную "фабрику" критических секций.
Гм??? А можно подробней?
... << RSDN@Home 1.1.3 beta 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[19]: thread safe singlton - возможно ли такое в принципе
От: Andrew S Россия http://alchemy-lab.com
Дата: 21.07.04 21:12
Оценка:
AS>>>Одну критическую секция на все? Несерьезно, тормоза будут дикие, более того может
L>>Совсем не обязательно. Можно, например, сделать шаблонную "фабрику" критических секций.
WH>Гм??? А можно подробней?

Как я понял, предлагается сделать синглтон (точнее, даже, фабрику), производящую объекты — критические секции По одной на каждый шаблонный класс синглтона. А уже ими пользоваться во второй проверке вместо авто лока (т.е. при захвате объека критической секции эта фабрика будет, защищаясь авто локом, в случае необходимости инициализировать критическую секцию — поскольку это быстро). Т.о. проблема частично решена введением дополнительного уровня абстракции. Остается дождаться, что кто-нибудь захочет поломать голову и найти баги в этой мысли — тогда придется вводить еще один уровень абстракции — фабрику фабрик критических секций и т.п.
Немного пояснений.
Как я понял — основные претензии к реализации авто лока у Lexey — это то, что "защищенный им код должен выполняться очень непродолжительное время". Это мягко говоря не так в случае win32 — там все вполне пристойно. А вот в линукс реализации используется декремент\инкремент при каждой "прокрутке", т.е. операция захвата выполняется не атомарно.
while( __exchange_and_add(&m_.a_, 1) ){
//  если в этот момент другой тред будет пытаться захватить автолок, наверняка будет бяка
  __atomic_add(&m_.a_, -1);
//  и в этот наверняка тоже :)
  sched_yield();
}

Но повторюсь, это конкретная реализация. Я, к сожалению, не знаю линукс настолько, чтобы судить о возможности там сделать по-другому (т.е. не инкрементом, а обменом), но, очевидно, операция установки флага "занятости" автолока должна быть атомарной, ни в первом, ни во втором
while( __exchange_and_add(&m_.a_, 1) ){
  __atomic_add(&m_.a_, -1);
  sched_yield();
}

(тут, правда, я смог придумать только вариант с MAX_UINT — 1 тредов, одновременно захватывающих автолок) приведенном варианте это не соблюдено.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.