vb.net - Double-checked locking not thread-safe? -


i've experienced odd behavior in wpf application, when using double-checked locking create thread-safe singleton. code represents usual implementation of technique:

  private _graphics contracts.interfaces.components.igraphics     readonly property graphics contracts.interfaces.components.igraphics                     if _graphics nothing                 synclock lock                     if (_graphics nothing)                         _graphics = new gfx.application()                     end if                 end synclock             end if             return _graphics         end     end property 

when running program, got exception, because application-object constructed twice. couldn't believe eyes, since understanding of how locks work, tells me should thread-safe.

my presumption was, code running twice on same thread (asynchronously), ended modifying code analyse problem. adding list in order put thread-object every time thread steps locking statement. next, had compare contained thread-object current thread:

readonly property graphics contracts.interfaces.components.igraphics             if _graphics nothing             synclock lock                 if (_graphics nothing)                     if (threadlist.any() andalso (threadlist.first() isnot threading.thread.currentthread))                         stop ' program stopping here.                     end if                     threadlist.add(threading.thread.currentthread)                     _graphics = new gfx.application() ' object construction takes around 70 ms.                 end if             end synclock         end if         return _graphics     end end property 

as might guess, program stopped, because multiple threads ran same locking statement. how can true? have absolutely no explanation behavior, let me know if have idea. thanks.

update: want add more details. initialization routine causes 2 anonymous methods run asynchronously. each of them accesses readonly property of singleton holder.

 task.factory.startnew(sub() graphics.init(...)  task.factory.startnew(sub() graphics.run(...) 

and here related disassembly instructions. perhaps give indication. here able follow these instructions:

 if _graphics nothing 002d91ed  cmp         dword ptr ds:[38e3430h],0   002d91f4  sete        al   002d91f7  movzx       eax,al   002d91fa  mov         dword ptr [ebp-48h],eax   002d91fd  cmp         dword ptr [ebp-48h],0   002d9201  je          002d9297                   synclock lock 002d9207  nop   002d9208  mov         eax,dword ptr ds:[038e3438h]   002d920d  mov         dword ptr [ebp-40h],eax   002d9210  mov         ecx,dword ptr [ebp-40h]   002d9213  call        518dce8c   002d9218  nop   002d9219  xor         edx,edx   002d921b  mov         dword ptr [ebp-44h],edx   002d921e  nop   002d921f  lea         edx,[ebp-44h]   002d9222  mov         ecx,dword ptr [ebp-40h]   002d9225  call        7301a2b0   002d922a  nop                       if _graphics nothing 002d922b  cmp         dword ptr ds:[38e3430h],0   002d9232  sete        al   002d9235  movzx       eax,al   002d9238  mov         dword ptr [ebp-48h],eax   002d923b  cmp         dword ptr [ebp-48h],0   002d923f  je          002d9264                           _graphics = new gfx.application() 002d9241  mov         ecx,47d664h   002d9246  call        73e601d2   002d924b  mov         dword ptr [ebp-4ch],eax   002d924e  mov         ecx,dword ptr [ebp-4ch]   002d9251  call        002d8c10   002d9256  mov         eax,dword ptr [ebp-4ch]   002d9259  lea         edx,ds:[38e3430h]   002d925f  call        73e52360                       end if 002d9264  nop                   end synclock 


Comments