Presentation is loading. Please wait.

Presentation is loading. Please wait.

Multithreading.NET a practical perspective Peter Ibbotson.

Similar presentations


Presentation on theme: "Multithreading.NET a practical perspective Peter Ibbotson."— Presentation transcript:

1 Multithreading.NET a practical perspective Peter Ibbotson

2 Why multi-thread?  With new dual core processors makes better use of the CPU  Keeps the User Interface responsive during long calculations.  Allows Asynchrous IO - Asynchronous Programming model (aka APM)  Single CPU systems can be slightly slower, but the user experience is better.

3 Why not multi-thread?  It's hard to do right.  Really it is!  Generates Heisenbugs very easily  Synchronisation is hard  Often you don't really need it  Talking to Windows forms controls is tricky  Threads aren't cheap

4 Thread basics I  Threads aren't "free"  They get 1MB of address reserved for stack + 12KB of kernel-mode stack  Each DLL in the parent process gets called to say a new thread has been created  Each DLL also gets called when a thread is about to die.  Context switches save / restore registers (700 bytes on x86, 1240 on x64) and use a spinlock so take time.

5 Thread basics II  Create a tread using ThreadStart passing in a delegate to call:  Thread Worker=new Thread(new ThreadStart(StartMethod));  Start the thread using Thread.Start();  Stop a thread using Thread.Abort()  Suspend a thread using Thread.Suspend();  Wait for a thread to complete using Thread.Join();

6 Example  Notes  Parameterised threads aren't always a good idea particularly as they aren't type safe.  Often better to create a whole class with local variables that you initialise before you start the thread.

7 Variables and caches  Two threads share variables BUT the cache gets in the way. Each one may not see the same value.  internal sealed class CacheCoherencyProblem { private byte m_init=0; private Int32 m_value=0; public void Thread1(){ m_value=5; m_init=1;} public void Thread2(){ if (m_init==1) WriteLine(m_value);} } In theory if you run this it may display 0, but this depends on cachelines

8 Variables and caches step 1  CPU1 runs Thread1 CPU2 Thread2  internal sealed class CacheCoherencyProblem { private byte m_init=0; private Int32 m_value=0; public void Thread1(){ m_value=5; m_init=1;} public void Thread2(){ if (m_init==1) WriteLine(m_value);} } CPU2 reads a byte from memory and it's before m_value fields bytes in memory, so both of them get read into cache. So CPU2 has m_value already in cache

9 Variables and caches step 2  CPU1 runs Thread1 CPU2 Thread2  internal sealed class CacheCoherencyProblem { private byte m_init=0; private Int32 m_value=0; public void Thread1(){ m_value=5; m_init=1;} public void Thread2(){ if (m_init==1) WriteLine(m_value);} } CPU1 runs Thread1 and changes m_value to 5 but this stays in cache, the following m_init=1 line gets written straight out to main memory

10 Variables and caches step 3  CPU1 runs Thread1 CPU2 Thread2  internal sealed class CacheCoherencyProblem { private byte m_init=0; private Int32 m_value=0; public void Thread1(){ m_value=5; m_init=1;} public void Thread2(){ if (m_init==1) WriteLine(m_value);} } Now CPU2 reads in m_init sees it's set to 1 and reuses the m_value from cache so m_value contains 0 and that is whats displayed

11 Sorry No demonstration  Sadly I couldn't get something like this to fail reliably  There are work arounds  Use VolatileRead & Write  Better yet use the C# keyword volatile.  Or just ignore it and use either  System.Threading.Interlocked  Monitor class and C# lock

12 The better idea use the monitor class  Quick demo of the problem  Example 2

13 The better idea use the monitor class  Quick demo of the problem  Example 2  Hopefully that race condition printed bingo a few times  The solution is to use C# lock statement  Back to the example

14 Monitor class and lock statement private void SomeMethod() { lock(this) { …. Access object } } Private void SomeMethod() { Object temp=this; Monitor.enter(temp); try { ….Access object } finally { Monitor.Exit(temp); }

15 Using locks in the real world  Don't do too many locks (Prefer locking larger objects)  Beware of nesting too deeply  Beware of deadlocking. Thread A acquires locks in this order Lock 1,2. Thread B acquires locks in this order Lock 2,1. On a bad day thread A has 1 locked and is waiting for 2 to become free. This will never happen as Thread B has lock 2 and is waiting for lock 1

16 Reader writer locks  ReaderWriterLock gives many readers access but only one writer.  Vance Morrison has more on this from the performance point of view  Use his version if performance is a problem from:  http://blogs.msdn.com/vancem/archive/20 06/03/28/563180.aspx

17 Thread pool  After all that don't create threads directly. They are quite expensive.  Use System.Threading.Threadpool instead.  The thread pool puts threads into two classes  Compute bound  IO bound  It adds threads to the pool in 500ms increments – See example (3)

18 Asynchronous Programming Model  It's a pattern for doing asynchronous callbacks when something completes (i.e. network, file io etc)  Always of the form BeginXxxx EndXxxx  BeginRead / EndRead for files  BeginConnect / EndConnect for sockets  Etc…  Always Call EndXxxx otherwise you'll leak  The callback is on a ThreadPool thread.  Time for an example (4)

19 Windows forms  An alternative to multi-threading  Use a modal dialog  Call DoEvents in loop while pooling the cancel button state.  Quick example (5)

20 Windows forms some VB6 tricks revisited  An alternative to multi-threading  Use a modal dialog  Call DoEvents in loop while pooling the cancel button state.  Quick example (5)  Other alternatives - use a WinForms timer and a state machine. The WinForms timer posts WM_TIMER messages on the main UI thread.

21 Sometimes even Microsoft go single threaded  Version 6 of the animation control stopped using a background worker thread now uses WM_TIMER  If the main window stops reading messages (DoEvents) there is a chance the animation control will stall trying to get the background colour  If the foreground process doesn't read messages then if another window sends a broadcast message, windows stops but the animation keeps running.  See http://blogs.msdn.com/oldnewthing/archive/2006/03/16/552821.aspx

22 Windows forms and threads (Examples stolen from chris sells)  "Thou shalt not operate on a window from other than its creating thread”  This means you need to use  Invoke or  BeginInvoke and EndInvoke  These transfer control back to the UI thread.  http://weblogs.asp.net/justin_rogers/article s/126345.aspx has a load of details  Example 6 and 7

23 Windows forms and threads (Examples stolen from chris sells)  "Thou shalt not operate on a window from other than its creating thread”  This means you need to use  Invoke or  BeginInvoke and EndInvoke  These transfer control back to the UI thread.  Adding a Cancel button  Example 8

24 ComponentModel.BackgroundWorker  Use this for simple background tasks  Simple to use and doesn't require BeginInvoke and friends

25 Multiple UI threads  Useful for things like reports  Use Application.Run from a new thread.

26 Further resources  Chris Sells MSDN articles  http://msdn.microsoft.com/library/en-us/dnforms/html/winforms06112002.asp  Jeffrey Richter – CLR via C# (book)  Vance Morrison  http://msdn.microsoft.com/msdnmag/issues/05/08/Concurrency/default.aspx  Invoke and friends  http://weblogs.asp.net/justin_rogers/articles/126345.aspx has a load of details  This powerpoint is at  http://www.ibbotson.co.uk/articles


Download ppt "Multithreading.NET a practical perspective Peter Ibbotson."

Similar presentations


Ads by Google