.NET threading in C# Training Highlights sharing
Jeffery’s training: .NET Threading in C#: Building Responsive, Reliable & Scalable Code.
I’d like to share some highlights with you. And the demo code is here: www.wintellect.com/2397
1. Introduction
- Early OS had just 1 thread, and then Windows supports multiple threads for robustness instead of performance.
- n Bad products use lots of threads but most of the time doing nothing (low CPU usage). For example: Movie Maker, Outlook and Visual Studio
- Threads are overhead
- Kernel objects in CPU registers: x86=~700bytes, x64=~1240bytes,IA64=~2500bytes
- User-mode stack: 1MB committed
- Kernel-mode stack:12KB/24KB
- For parameter/local var, exception-handling chain: …
- Dll attach/detach notifications: hundreds of functions are called
- Window pre-empts running thread and schedules another (non-waiting) thread each quantum (~20ms), which is called a context switch. Every context switch requires that Windows
- Enter kernel mode (very expensive)
- Save registers from CPU to running thread’s kernel object (x86=~700bytes, x64=~1240bytes,IA64=~2500bytes)
- Determine which thread to schedule next. If thread owned by other process, switch address space (very expensive)
- Load register from selected thread’s kernel object into CPU
- Leave kernel mode.
- Conclusion
- avoid threads: they are time/memory overhead
- use threads: they enable robustness & scalability on multi-CPU system
- Using thread
- Framework class library has 2 namespaces for process/thread
- Discourage: System.Diagnostics(Process & ProcessThread), providing Windows’view
- Encourage: System.Threading(Thread), providing CLR managed view
- Constructing one thread doesn't have Windows create a thread. Instead, Start() does.
- Sleep(Timespan timeout) suspends a thread at least timeout timespan.
- Every thread has a base priority number, 0(lowest & reversed) to 31(highest), Windows boosts a thread’s priority when an event occurs.
- Windows Thread vs CLR Thread
- Thread’s ManagedThreadId in CLR differs from ProcessThread’s Id in Windows
- Some properties are only in Windows, such as ProcessorAffinity, useful to assign task to a specific processor.
- Some properties are only in CLR, such as IsBackground(true if thread won’t force app to stay alive)
- Threading support in VS
- Thread window
- You can select which thread to step through
- You can freeze/thaw threads to take them out of the picture
2. Performing Asynchronous Operations with the CLR’s Thread Pool
- There is one ThreadPool per process, shared by all AppDomains.
- If work items queue quickly, more threads are created; If work items reduce, a ThreadPool thread waits 2 minutes, wake and kills itself.
- Thread pools should never have a max thread limit
- There are mainly 2 kinds of task need thread
- Compute-Bound
- When to create your own thread instead of using threadpool
- Non-normal thread priority
- Foreground thread to keep app alive until work item is done
- Long-running compute-bound task
- Aborting the operation
- Periodically performing asynchronous compute-bound operation: System.Threading.Timer. 2 more timers:
- System.Windows.Forms.Timer: all work is done by just 1 thread
- System.Timers.Timer: System.Threading.Timer ‘s wrapper to support VS design time operation.
- When to create your own thread instead of using threadpool
- I/O-Bound
- Compute-Bound
3. The CLR’s Asynchronous Programming Model
- CLR creates 1 IOCP per process and creates thread pool threads that wait on the IOCP.
- Standard pattern to execute asynchronous operations
- I/O-bound: BeginXXX for many classes, such as Stream, Dns, Socket, WebRequest, SqlCommand
- Computer-bound: BeginInvoke
- If you don't’ specify the FileOptions.Asynchronous flag, Windows performs synchronous operations, which is very inefficient.
- Windows always performs some File I/O operations synchronously: Compression, Extending a file’s length by appending, Cached data.
- APM supports 3 rendezvous techniques
- Wait until done: BeginXXX and then EndXXX
- Polling: BeginXXX, and then call IAsyncResult.IsCompleted repeatedly, and then EndXXX
- Callback:
- I/O-bound: BeginXXX, ThreadPool thread calls device, ThreadPool thread back to ThreadPool, … callback, EndXXX
- Compute-bound: BeginInvoke, ThreadPool thread works, EndInvoke
- Exception
- BeginXXX throw exception: no item queued
- Operation fails: EndXXX will throw exception
- APM Usage Note
- Must call EndXXX or you will leak resources.
- Just call EndXXX once or result is unpredictable.
- Call EndXXX with the same object used by BeginXXX or you will get InvalidOperationException
- Many Win32 API don’t offer async versions
- WinForm and WPF GUI only can be updated in thread who creates the windows. This is not APM
- WebForm can be configured as async rendering in ASP.NET 2.0: Async=”true” as page directive in aspx file and some BeginXXX, EndXXX methods.
4. The Event-Based Asynchronous Programming Model
- To simplify APM, Windows Forms team produced this. http://msdn2.microsoft.com/en-gb/library/ms228966.aspx
- Jeffery and many teams disagree with this.
5. Thread Synchronization
- Thread safety
- All static Framework Class library are thread safe
- Framework Class library Instance methods are usually not thread safe.
- .NET Fx v1.x collections had confusing thread-safe wrappers, which have been removed in .NET Fx 2.0 (ArrayList.Synchronized(new ArrayList());)
- Code optimization by c#/JIT complier and CPU reordering may execute your code out of program order.
- VolatileRead/VilotileWrite/memory barrier(memory fence)
- Avoid using volatile keyword
- Manipulate an Int32 in a thread-safe way: Interlock
- Monitor, lock
- Double-check locking technique
- ReaderWriterLock
- Window Kernel Objects
- System.Threading.WaitHandle (Mutex,Semaphore, EventWaitHandle(AutoResetEvent/ManualResetEvent))
- ThreadPool offers an efficiend way to execute a method when a kernel object becomes signaled:ThreadPool.RegisterWaitForSingleObject
- Conclusion
- Always do async I/O, because sync I/O blocks a thread.
- Avoid using a thread for a dedicated task, because it blocks unless task runs at 100% CPU utilization continuously.
- Avoid using thread synchronization constructs, because they can block a thread.
- Use volatile Reads/Writes & Interlocked methods, because they are extremely fast, never block a thread.
6. The Art of Thread Synchronization. Referring to his book and free power threading library
7. Aborting a Thread