C# Threading
< Prev 1 2 3 4 Next >
- Simple multithreaded example in c#. The method passed as the ThreadStart delegate can have no arguments and must return void.
This producesusing System; using System.Threading; public class ThreadTest { public class MyJob { public int repetitions=1; public void runme() { for(int i=0;i<repetitions;i++) { Thread.Sleep(1000); Console.WriteLine(Thread.CurrentThread.Name); } } } public static void Main(string[] args) { MyJob myJob = new MyJob(); myJob.repetitions=3; Thread thread = new Thread(new ThreadStart(myJob.runme)); thread.Name = "first"; thread.Start(); MyJob myJob2 = new MyJob(); myJob2.repetitions=5; Thread thread2 = new Thread(new ThreadStart(myJob2.runme)); thread2.Name = "second"; thread2.Start(); } }
first second first second first second second second
- Concurrency When two threads change the same data, bad things(tm) can happen. In the following example two threads increment and then decrement a global variable. In C# incrementing and decrementing are not necessarily atomic.
The results can be:using System; using System.Threading; public class ThreadTest2 { public class MyJob { public static int counter = 0; public int repetitions=100000000; public void runme() { for(int i=0;i<repetitions;i++) { counter++; counter--; } Console.WriteLine(Thread.CurrentThread.Name+": "+counter); } } public static void Main(string[] args) { MyJob myJob = new MyJob(); Thread thread = new Thread(new ThreadStart(myJob.runme)); thread.Name = "first"; MyJob myJob2 = new MyJob(); Thread thread2 = new Thread(new ThreadStart(myJob2.runme)); thread2.Name = "second"; thread.Start(); thread2.Start(); } }
or sometimesfirst: 0 second: 0
We can never be sure of the outcome. We can overcome this in several ways.first: 1 second: 0
- Using Threading.Interlocked methods. Using Threading.Interlocked.Increment the CLR will guarentee an atomic operation. Another interesting method in the namespace is "Exchange()" which swaps two values atomically.
The results will be:public class MyJob { public static int counter = 0; public int repetitions=100000000; public void runme() { for(int i=0;i<repetitions;i++) { System.Threading.Interlocked.Increment(ref i); System.Threading.Interlocked.Decrement(ref i); } Console.WriteLine(Thread.CurrentThread.Name+": "+counter); } }
first: 0 second: 0
- Using "lock()" to synchronize lock() takes an object as the argument. In this example we can use "this" since both threads are using the same "MyJob" instance. In static functions you can use the "type" object, e.g., "lock(typeof(Util))" to synchronize.
public class MyJob { public static int counter = 0; public int repetitions=100000000; public void runme() { lock(this) { for(int i=0;i<repetitions;i++) { counter++; counter--; } } Console.WriteLine(Thread.CurrentThread.Name+": "+counter); } }
- The Synchronization attribute can be used.This locks the entire object - everything is single access. Note the object must descend from ContextBoundObject.
[System.Runtime.Remoting.Contexts.Synchronization] public class MyJob: ContextBoundObject { public static int counter = 0; public int repetitions=100000000; public void runme() { for(int i=0;i<repetitions;i++) { counter++; counter--; } Console.WriteLine(Thread.CurrentThread.Name+": "+counter); } }
- Example of using Join() Join() hitches the fate of a thread to the current thread. Execution of the calling thread will wait until the callee's process completes. In this example we Join on a thread that takes 2 seconds to complete, then Join on a second that still has 2 seconds to go.
This producesusing System; using System.Threading; //Example showing use of Join() public class ThreadTest4 { public class MyJob { public static int counter = 0; public int waitfor=1; public int finalState = -1; //sleeps then fills in finalState to simulate work done public void runme() { Thread.Sleep(waitfor); finalState = waitfor; Console.WriteLine(Thread.CurrentThread.Name+" finished sleeping finalState: "+finalState); } } public static void Main(string[] args) { MyJob myJob = new MyJob(); myJob.waitfor = 2000; Thread thread = new Thread(new ThreadStart(myJob.runme)); thread.Name = "first"; MyJob myJob2 = new MyJob(); myJob2.waitfor = 4000; Thread thread2 = new Thread(new ThreadStart(myJob2.runme)); thread2.Name = "second"; thread.Start(); thread2.Start(); Console.WriteLine("After start."); Console.WriteLine("Before first join."); thread.Join(); Console.WriteLine("After first join."); Console.WriteLine("Before second join."); thread2.Join(); Console.WriteLine("After second join."); Console.WriteLine("myJob.finalState="+myJob.finalState); Console.WriteLine("myJob2.finalState="+myJob2.finalState); } }
After start. Before first join. first finished sleeping finalState: 2000 After first join. Before second join. second finished sleeping finalState: 4000 After second join. myJob.finalState=2000 myJob2.finalState=4000
- Join() with timeout What if a process may never finish? The Join() method has an optional parameter specifying how many millisecs to wait. The Join will give up after that time and return a 'false'. The following example shows the main thread waiting 2 seconds for a job that will take 8 seconds. After waiting 2 seconds, it gets a 'false' value back implying it did not finish in 2 seconds. Lacking any mercy we waste the process and move on to wait for the second, which has already completed.
Which produces:using System; using System.Threading; //Example showing use of Join() public class ThreadTest6 { public class MyJob { public static int counter = 0; public int waitfor=1; public int finalState = -1; //sleeps then fills in finalState to simulate work done public void runme() { Thread.Sleep(waitfor); finalState = waitfor; Console.WriteLine(Thread.CurrentThread.Name+" finished sleeping finalState: "+finalState); } } public static void Main(string[] args) { MyJob myJob = new MyJob(); myJob.waitfor = 8000; Thread thread = new Thread(new ThreadStart(myJob.runme)); thread.Name = "first"; MyJob myJob2 = new MyJob(); myJob2.waitfor = 500; Thread thread2 = new Thread(new ThreadStart(myJob2.runme)); thread2.Name = "second"; thread.Start(); thread2.Start(); Console.WriteLine("After start."); Console.WriteLine("Before first join."); bool finished = thread.Join(2000); if(!finished) { thread.Abort(); } Console.WriteLine("finishedP:"+finished); Console.WriteLine("After first join."); Console.WriteLine("Before second join."); thread2.Join(2000); Console.WriteLine("After second join."); Console.WriteLine("myJob.finalState="+myJob.finalState); Console.WriteLine("myJob2.finalState="+myJob2.finalState); } }
After start. Before first join. second finished sleeping finalState: 500 finishedP:False After first join. Before second join. After second join. myJob.finalState=-1 myJob2.finalState=500
No comments:
Post a Comment