Inorder for us not to get lost, my discussion is with respect to C#.NET, kamsky is base on JAVA.
in C# synchronized is just a mechanism...or take it just a simple word that describes what is happening/doing in your application, there is a lot of ways to achieved that...
sakto ka sa suggestion na i-lock kung mag-write, if you have 100 threads, one of them are racing to instantiate the singleton class, its either you will...
lock the object (there are numbers of ways to lock in C#, some of it I tested and found some holes that it is dangerous in some scenarios)
or
Synchronized your threads (nolocking)... if ThreadD is currently accessing Singleton Class, the rest of the threads should know about that... (in multi application domain, if another threads came from different domain. that's a problem already) think about the PRINTSERVER spooler... we have multiple machine accross the network, and multiple applications, and another applications on the server itself.
how about combining both? locking and synchronization? I find this interestingin C++ I used to wait the handle via windows API... and C#.NET I can easily monitor
![]()
guys why are you so concern about the overhead? , in every solution there is always a trade off.
…Afraid that their application might be bloated?
at small scale overhead is not an issue but for bigger scale this performance issue should not be ignored.
If you read the article about, had it been facebook written in c++ instead of PHP, the 30,000 servers could be reduced to 7500. Imagine the environment and financial impact for that.
(I know it doesnt mean financial impact, because C++ debugging could take time too)
This would apply to other application too if you can save microseconds. And this wouldnt take time to implement because it's been an implementation pattern already (idioms) and documented else where.
PS. This thread is fun to thread, you will learn new things, new developers perspective and even proving that multiple instances could occur in most singleton implementations. That's a nice experiment there Mark.
that would be great, but you should also consider the funds involve when facebook started.If you read the article about, had it been facebook written in c++ instead of PHP, the 30,000 servers could be reduced to 7500. Imagine the environment and financial impact for that.
software development is not about delivering the ultimate solution on the first drop.
its all about making value of your money and concept, its not about the best PL to use in implementing a solution.
hehehe maybe Mark should create a test app to test a thread safe singleton and computing the overhead that is caused by locking?PS. This thread is fun to thread, you will learn new things, new developers perspective and even proving that multiple instances could occur in most singleton implementations. That's a nice experiment there Mark.
instead of testing a non thread safe singleton and proving it to fail in a threaded environment which is too obvious hehehe. IMO
as for locking, this stuff cannot be avoid when you are dealing with multi-threaded applications. even on databases there are cases when you can only make a situation work through table locking.
that is all i want to really say![]()
ok... I'm looking forward on this.... but first! Anyone here can share some idea on how would you get the total waiting time of the thread before acquiring the locked object? I just need a plain/simple/quick explanation...
There are a lot of ways to implement locking in unmanaged world and more in managed environment like C#.NET, and this will affect the overall system performance…
With respect to LOCKING… I remember, I posted several time events in multi-threaded applications. https://www.istorya.net/forums/progra...actices-6.html
LOCKING - works at speed of nanoseconds, but in managed world, I guess it is already closer to microseconds.
BLOCKING – works at speed of microseconds, no doubt. (TESTED!) I used to have a 0 -3ms benchmarks blocking 2-5 threads.
OS Thread Scheduling – invokes at speed of milliseconds (Short-term scheduler), but take note that this kind of scheduling is not related to Preemptive/ Non-Preemptive, that one is with respect to process already.
In theory, there is no overhead in locking objects, just try to consider how fast a nanosecond is… speed of light? Theory of relativity? The overhead may only appear if one will not take it seriously in designing the application. With numbers of ways to lock objects, I tried the commonly used approach.
And here are my findings:
[B]SINGLETON WITHOUT LOCK
LOWEST RATE: 0MS (I believe this is in nanoseconds)
HIGHEST RATE: 3MS (always because of different calls, and thread cycles, if no output required this would be at microseconds)
Code:T_0 is accessing singleton class without lock T_0 is now initializing Singleton class T_1 is accessing singleton class without lock T_1 is now initializing Singleton class T_2 is accessing singleton class without lock T_2 is now initializing Singleton class T_3 is accessing singleton class without lock T_3 is now initializing Singleton class T_4 is accessing singleton class without lock T_4 is now initializing Singleton class T_0 Done... This is T_0 - Singleton: 63835064 - Total Time Acquired: 3ms T_1 Done... This is T_1 - Singleton: 6044116 - Total Time Acquired: 3ms T_2 Done... This is T_2 - Singleton: 4032828 - Total Time Acquired: 3ms T_3 Done... This is T_3 - Singleton: 35320229 - Total Time Acquired: 3ms T_4 Done... This is T_4 - Singleton: 12547953 - Total Time Acquired: 3ms Press any key to continue . . .
SINGLETON WITH LOCK
LOWEST RATE: 1MS (this is microseconds/or perhaps nanoseconds?)
HIGHEST RATE: 16MS (microseconds, perhaps kernel was busy and exhausted?)
Code:T_0 is now initializing Singleton class T_0 is accessing singleton class with lock This is T_0 - Singleton: 63835064 - Total Time Acquired: 16ms T_1 is accessing singleton class with lock This is T_1 - Singleton: 63835064 - Total Time Acquired: 16ms T_2 is accessing singleton class with lock This is T_2 - Singleton: 63835064 - Total Time Acquired: 16ms T_3 is accessing singleton class with lock This is T_3 - Singleton: 63835064 - Total Time Acquired: 16ms T_4 is accessing singleton class with lock This is T_4 - Singleton: 63835064 - Total Time Acquired: 16ms Press any key to continue . . .
Revised Codes:
Code:public static Singleton getInstance(){ if (Singleton.withLock) { Singleton.timeSpan.Start(); lock (padlock) { Console.WriteLine("{0} is accessing singleton class with lock", Thread.CurrentThread.Name); if (MyInstance == null) { MyInstance = new Singleton(); } Console.WriteLine("{0} Done...", Thread.CurrentThread.Name); return MyInstance; } } else { Singleton.timeSpan.Start(); Console.WriteLine("{0} is accessing singleton class without lock", Thread.CurrentThread.Name); if (MyInstance == null) { MyInstance = new Singleton(); } Console.WriteLine("{0} Done...", Thread.CurrentThread.Name); return MyInstance; }
NOTE: These numbers will gone up higher if more than 5 threads were involved (same machine of course!)
Revised Codes:
Code:public static void TestSingleton(object o) { Singleton s = Singleton.getInstance(); Singleton.timeSpan.Stop(); if (!Singleton.IsDone) Console.WriteLine("This is {0} - Singleton: {1} - Total Time Acquired: {2}ms", Thread.CurrentThread.Name, s.GetHashCode(), Singleton.timeSpan.ElapsedMilliseconds); else Console.WriteLine("This is {0} - Singleton: {1} - Total Time Acquired: {2}ms", Thread.CurrentThread.Name, s.GetHashCode(), Singleton.timeSpan.ElapsedMilliseconds); }
Are you having the same codes I posted above? You better begin constructing a new one. :P
again, anyone here can share some idea on how would you get the total waiting time of the thread before acquiring the locked object? I just need a plain/simple/quick explanation...
@silent-kill, I wrote the previous code, just to proved that, it is possible to have multiple instances in multi-threaded environment.
hi mark, may i ask how are you computing time?
i believe all standard time measuring class in .net works in milliseconds.
also note that when you do Console.WriteLine this is quite expensive task since its doing IO.
i would like to know the elapse time when the thread request for a lock until i gets the lock only.
can you send me your test app so i can play with it?
you can try this, classes its more accurate than doing timespan
so i think... do get the total elapse time of all threads acquiring the lock yo do something like this.Code:[System.Security.SuppressUnmanagedCodeSecurity] [DllImport("kernel32")] private static extern bool QueryPerformanceFrequency(ref long PerformanceFrequency); [System.Security.SuppressUnmanagedCodeSecurity] [DllImport("kernel32")] private static extern bool QueryPerformanceCounter(ref long PerformanceCount);
you need static hash table declared somewhere LOL
don't do any console.writeline inside the class. do it after all metrics has been recorded.Code:hashStart[<threadID>] = GetCurrentTime lock(aquirelock) { hashElapse[<threadID>] = hashStart[<threadID>] - GetCurrentTime }
also this could vary on how many threads your running due to cpu scheduling not all threads may be executed at the same time some may be waiting.
Yup, your right, that's why I noted that if there are no "output" this would be at microseconds, I put it that way, since we need to know the value of the Singleton Instance.
how about storing thread-specific data privately using (TLS) AllocateDataSlot, AllocateNamedDataSlot, or GetNamedDataSlot? each of the threads may have a private data, rather than make use of I/O calls. coz we cannot guarantee how long they've been waiting to get a copy of an object,investigating with QueryPerformanceCounter, upon entering/exiting... so at the end of the execution we can examine the singleton objects carried by different threads...
We are using Win32API here, I hope it isn't expensive for CLR going out to unmanaged environment, and getting the result right before it exits, as the CLR might be doing some few operations on this; like placing some attribute[System.Security.SuppressUnmanagedCodeSecurity] and mapping with "kernel32" functions, in short, overhead on API CALLS.
From How To Use QueryPerformanceCounter to Time Code
Code:Function Units Resolution ------------------------------------------------------------------------------------------------------ Now, Time, Timer seconds 1 second GetTickCount milliseconds approx. 10 ms TimeGetTime milliseconds approx. 10 ms QueryPerformanceCounter QueryPerformanceFrequency same
Debug/Immediate window.
We already notice the overhead outside managed environment, by just looking at API calls... how about calling/invoking this from Managed environment?
SOME SORT OF COMPARISON: image here: hxxp://rapidshare.com/files/325562746/kernelvsclr.JPG.html
CODE:
OUTPUT:Code:using System; using System.Runtime.InteropServices; using System.Diagnostics; using System.Threading; class Program { [DllImport("kernel32")] public static extern uint GetTickCount(); public static void Main() { Stopwatch w = Stopwatch.StartNew(); // CLR time already start counting. uint start = GetTickCount(); // this should appear more early than our stopwatch managed by CLR. Thread.Sleep(1); Console.WriteLine("\nElapsed Kernel: {0}ms", GetTickCount() - start); //stopwatch still counting //Thread.Sleep(1); Console.WriteLine("\nElapsed CLR: {0}ms", w.ElapsedMilliseconds); //finally read our stopwatch. } }
by the way, I checked the responsible codes, upon calling up the unmanged procedures/functions...SSCLI20 \ CLR \ SRC \ VM folder: "DLLIMPORT", ", "DLLIMPORTCALLBACK" files (.CPP and .H), this is part of Virtual Machine - CLR codes.
FROM LINES ON DLLIMPORT.CPP
Code:// this function is called by CLR to native assembly stubs which are called by // managed code as a result, we need an unwind and continue handler to translate // any of our internal exceptions into managed exceptions. INSTALL_UNWIND_AND_CONTINUE_HANDLER; DWORD dwStubFlags = NDIRECTSTUB_FL_CONVSIGASVARARG | NDIRECTSTUB_FL_BESTFIT; MethodDesc* pMD = NULL; CorPinvokeMap unmgdCallConv = pmNoMangle; if (fVarargPinvoke) { unmgdCallConv = pmCallConvStdcall; } else { switch (MetaSig::GetCallingConvention(pVASigCookie->pModule, pVASigCookie->mdVASig)) { case IMAGE_CEE_CS_CALLCONV_C: unmgdCallConv = pmCallConvCdecl; break; case IMAGE_CEE_CS_CALLCONV_STDCALL: unmgdCallConv = pmCallConvStdcall; break; case IMAGE_CEE_CS_CALLCONV_THISCALL: unmgdCallConv = pmCallConvThiscall; break; case IMAGE_CEE_CS_CALLCONV_FASTCALL: unmgdCallConv = pmCallConvFastcall; break; default: COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV); } }
1. they make use of p/invoke to call unmanaged codes. PInvoke is a wrapper class library for the most widely used Win32 API calls.
2. then construct the switch statement, to determine that calling conventions, check it here: x86 calling conventions - Wikipedia, the free encyclopedia you can find the STDCALL, THISCALL, FASTCALL and more on that actually... if we are talking about standard x86 calls.
and the result is implemented via DELEGATE, with built-in security procedures... in areas that if the return value will not match from the callee-caller's ID in appdomain's table...maybe, CLR is capable of blocking the injected values? I hope so...This the only overhead I can see, security calls is not overhead if you need it badly duh. maybe there's another attribute to tagged our code and prioritized by CLR, or disregard the other events.
the previous code I made is the ugliest approach I can think of...there's another way of achieving that.
so much on this for now, much more for my brain on christmas day LOL....
Merry Christmas everyone... Have Fun... cheers....!!!
Last edited by MarkCuering; 12-25-2009 at 08:25 PM. Reason: opss... i paste wrong code sorry.... hehehe
Similar Threads |
|