.NET Tips: Threads
back to content
· One of the registers stored in the TLS is a program counter that tells the thread which instruction to execute next.
· int is atom if align was not changed, but Interlocked.Increment() is not.
· Thread.Suspend is deprecated, because it suspends the hardware thread, at whatever position it is currently being executed. >>
· Threads in ThreadPool are saved with their thread's priority.
· ThreadPool's Thread is background, so if you exit from app, threads will be abandoned.
· Unhandled exception in thread terminates thread and shutdowns hosting process (only in .net 2.0), only ThreadAbortException is out of this rule.
· ThreadPood isn't used it the remoting scenarios - completion IO port thread (from 2 to 6) used instead.
· DataTable.Select() considered as write operation(change some internal structs), not read.
· In .NET 2.0 unhandled exception on any thread shuts down the whole application.
· In .NET 2.0 SP1 the threadpool's default max thread count was increased to 250/CPU to statistically reduce the frequency of accidental and nondeterministic deadlocks. >>
· X86 JIT guarantee that no "orphaned" locks happen, when X64 JIT isn't. For X64 JIT use Monitor.ReliableEnter(). >>
· New threads in ThreadPool are created with 500ms delay, if "minimum" number of threads was surpassed.
· A thread context switching costs 2,000–8,000 cycles. >>
· Win32 evens has advantage over Monitor.Wait, Pulse, and PulseAll: once event has been signaled, any subsequent waits will immediately unblock, even if the threads had not begun waiting before the signal occurred. >>
[MethodImpl(MethodImplAttributes.Synchronized)] is equal to lock(this).
Advantage of Mutex is that it can be named that is useful in debugging and has "abandonded mutex" feature to keep mutex even if process crashed.
Registration EventHandler in the class that EventHandler owns break thread safety, because Combine, that is unsafe and provided by .NET FW, is called instead of add_.
class provides thread-safety for events registration, while struct doesn't.
using statement puts some initialization code before auto-generated try block, thus it weaks handling asynchronous exceptions. In that case put try...finally block by hand. But using guarantees to close resources even exception was thrown.
Monitor class uses space in the object header and/or the object's sync-block to record exclusive ownership of the lock. >>
Don't lock on typeof/string because you can end up with the domain-neutral objects shared all AppDomains in the process (for example String and Thread objects). In result we can get deadlocks because same object and thus the same lock will be shared between domains. >>
Prefer to use Thread.Sleep(1) in lieu of Thread.Sleep(0) for the saturated context to avoid race, because Sleep(0) gives up the thread's time-slice if a thread at equal priority is ready to run. >>
Pulse() will own the lock on for some time after the call, yet the thread that called Wait() will immediately wake after the Pulse and try to acquire this lock (failing and waiting). If you’re using PulseAll, this could have a noticeable (and in some cases, dramatic) impact on scalability. Windows uses priority boosts to “hand off” the current time-slice to the recipient of an event signal. >>
Use spin wait instead of blocking if the condition the thread is waiting for occurs in fewer than time of two context switching. SpinWait sample is here >>
Use "volatile" to restrict the reordering of memory access
"volatile" field is restricted for the memory access reordering. A write to a volatile field is always done after all other memory accesses which precede in the instruction sequence. A read from a volatile field is always done before all other memory accesses wich occur after it in the instruction sequence. >>
new Prefer to use the "one-time initialization" feature of Vista over the double-locking singleton to init the shared resource once. >>
Be very careful changing the number of min/max thread of thread pool and validate the result of the method call. For example, when you want to avoid the "warm-up" time of the idle thread from the thread pool you do the ThreadPool.SetMinThreads(50, 1000) and ThreadPool.SetMinThreads(5, 1000) calls. On the single process machine the result will be wrong - first call returns false, because only 25 threads are available in the pool. >>
When you read several non-volitile variables sequentially, which were interlocked take into account that JIT may change the sequence of the reading and the latest variable will be interlocked first. So, don't rely on the proper sequential result >>
Declare the variable, which are used in anonymous methods explicitly to avoid variable being shared in multithread environment. >> Consider the following sample
foreach (string url in urls)
Anonymous methods do not capture read-only locals at a point in time, instead they actually capture the local by putting it on the heap, to share it between the outer method and all anonymous methods. This behavior can have place without working in multithread environment.
To fix this, just declary url string explicitly
for (int i = 0; i < urls.Length; i++)
string url = urls;
back to content