300 likes | 484 Views
Concurrent programming. Threads Introduction Synchronization. Threads. System.Threading namespace Some properties on threads Creation of threads Synchronization Lock Monitor [Syncronization] Timer callback ThreadPool. Threads and processes. A process has at least one thread.
E N D
Concurrent programming • Threads • Introduction • Synchronization
Threads • System.Threading namespace • Some properties on threads • Creation of threads • Synchronization • Lock • Monitor • [Syncronization] • Timer callback • ThreadPool
Threads and processes • A process has at least one thread. • Threads might run concurrently • Threads shares resources within the process • Therefore they can communicate directly • Threads are normally controlled by the OS • Processes are isolated from each other. • Processes has its own resources allocated • Processes can not communicate directly but has to use signalling, socket etc. • Processes can run on different processors and domains
System.Threading • .NET offers a several classes for thread handling • Some classes: • Thread: encapsulates a thread. Contains also static properties and methods ie. CurrentThread and Sleep(). • Monitor: Synchronization with locks and wait. • Semaphore: Used for limiting the number of threads that concurrently uses a ressource • Mutex: Used for synchronisering between threads. • Timer: Makes et possible to execute a method by a given time interval • TimerCallback: Delegate, used with Timer • ThreadState: Enum type with possible states on the thread • ThreadPriority: Enum type with possible priorities on the thread • ThreadPool: Makes it possible to access a CLR thread pool in a process
Class Thread • Constructor with ThreadStart delegate • Setting/getting the priority • Current state • Properties liveliness, background • Methods for controlling the thread • Gets the currently running thread public sealed classThread { publicThread(ThreadStart start); public ThreadPriority Priority {get; set;} public ThreadState ThreadState {get;} public boolIsAlive {get;} public boolIsBackground {get; set;} publicvoidStart(); publicstaticvoidSleep(int time); publicvoidSuspend(); publicvoidResume(); publicvoidJoin(); publicvoidInterrupt(); publicvoidAbort(); publicstaticvoidResetAbort(); publicstatic Thread CurrentThread {get;} } Note: Suspend and Resume are deprecated
Example: Statistics on CurrentThread Console.WriteLine("***** Primary Thread stats *****\n"); // Obtain and name the current thread. Thread primaryThread = Thread.CurrentThread; primaryThread.Name = "ThePrimaryThread"; // Show details of hosting AppDomain / Context. Console.WriteLine("Name of current AppDomain: {0}", Thread.GetDomain().FriendlyName); Console.WriteLine("ID of current AppDomain: {0}", Thread.GetDomainID()); Console.WriteLine("ID of current Context: {0}", Thread.CurrentContext.ContextID); // Show stats about this thread. Console.WriteLine("Thread Name: {0}", primaryThread.Name); Console.WriteLine("Has thread started?: {0}", primaryThread.IsAlive); Console.WriteLine("Priority Level: {0}", primaryThread.Priority); Console.WriteLine("Thread State: {0}", primaryThread.ThreadState);
Create a new thread • Make a method that shall be used when starting the thread. Similar to implementing Start() in Java. • Make a ParameterizedThreadStart delegate, and use the method as parameter to the constructor • Instanstiate a new thread object and use the delegate as the parameter to the constructor • Set properties for the thread (name, priority etc.) • Call theThread.Start() method.
ParameterizedThreadStart . Represents the method that executes on a Thread. Namespace: System.Threading public delegate void ParameterizedThreadStart ( Object obj ) Parameters obj An object that contains data for the thread procedure.
Create thread with ParameterizedThreadStart (step 1) Used as parameters to Add (Object obj). Therefore a and b has to be encapsulated using System.Threading; class AddParams { public int a,b; public AddParams(int numb1, int numb2) { a = numb1; b = numb2; } } class Program { public static void Add(Object data) { if (data is AddParams) {//Check that data is the type AddParams Console.WriteLine("ID of thread in Add(): {0}", Thread.CurrentThread.GetHashCode()); AddParams ap = (AddParams)data; Console.WriteLine("{0} + {1} is {2}", ap.a, ap.b, ap.a + ap.b); } }con't.... Add are used as a callback method, therefore the Object
Create thread with ParameterizedThreadStart (step 2-5) static void Main(string[] args) { Console.WriteLine("***** Adding with Thread objects *****"); Console.WriteLine("ID of thread in Main(): {0}", Thread.CurrentThread.GetHashCode()); AddParams ap = new AddParams(10, 10); //Step 2 and 3 Thread t = new Thread(new ParameterizedThreadStart(Add)); //Step 4 //Set evt. properties here, e.g. t.Name="MyThread"; //Step 5 t.Start(ap); // Do other work on Main() here. Console.ReadLine(); }
Synchronization • Synchronization can be implemented in mutiple ways: • the lock(Object obj) {...} keyword lock a critical sector (the compiler implements lock by a Monitor object) • the Monitor class are used for locking a critical sector by the static methods Monitor.Enter (Object obj) and Monitor.Exit (Object obj). • the obj parameter is a token. The thread that has the the token is allowed to run. • The Semaphore class makes it possible for a limited number of thread can access the same ressource in the same time. • The Mutex class avoids that multiple threads can access the same ressource in the same time. This is done by signalling. • [Synchronization] synchronizes on object level. Similar to synchronize in Java • Interlocked offers a atomar and thread safe increment and decrement af a variable.
Example: lock public class Printer{ public void PrintNumbers() { lock (this) { // Display Thread info. Console.WriteLine("-> {0} is executing PrintNumbers()", Thread.CurrentThread.Name); // Print out numbers. Console.Write("Your numbers: "); for (int i = 0; i < 10; i++) { Random r = new Random(); Thread.Sleep(1000 * r.Next(5)); Console.Write(i + ", "); } Console.WriteLine(); } } }
Example: lock (2) static void Main(string[] args) { Console.WriteLine("***** Synchronizing Threads *****\n"); Printer p = new Printer(); // Make 10 threads which are all pointing to the same // method on the same object. Thread[] threads = new Thread[10]; for (int i = 0; i < 10; i++) { threads[i] = new Thread(new ThreadStart(p.PrintNumbers)); threads[i].Name = string.Format("Worker thread #{0}", i); } // Now start each one. foreach (Thread t in threads) t.Start(); Console.ReadLine(); }
Same example with Monitor public class Printer{ public void PrintNumbers() { Monitor.Enter(this); // Display Thread info. Console.WriteLine("-> {0} is executing PrintNumbers()", Thread.CurrentThread.Name); // Print out numbers. Console.Write("Your numbers: "); for (int i = 0; i < 10; i++) { Random r = new Random(); Thread.Sleep(1000 * r.Next(5)); Console.Write(i + ", "); } Console.WriteLine(); Monitor.Exit(this); } }
Example: Semaphore public class Example{ // A semaphore that simulates a limited resource pool. private static Semaphore _pool; // A padding interval to make the output more orderly. private static int _padding; public static void Main(){ // 0 angiver antal frie tokens. Dvs Main holder ved start alle 3 tokens. _pool = new Semaphore(0, 3); // Create and start five numbered threads. for (int i = 1; i <= 5; i++) { Thread t = new Thread(new ParameterizedThreadStart(Worker)); t.Start(i); } Thread.Sleep(500); // Wait for half a second // Frigør de 3 tokens Main holder Console.WriteLine("Main thread calls Release(3)."); _pool.Release(3); Console.WriteLine("Main thread exits."); Console.ReadLine(); }
Example: Semaphore (2) private static void Worker(object num) { // Each worker thread begins by requesting the semaphore. Console.WriteLine("Thread {0} begins and waits for the semaphore.", num); _pool.WaitOne(); // A padding interval to make the output more orderly. int padding = Interlocked.Add(ref _padding, 100); Console.WriteLine("Thread {0} enters the semaphore.", num); // The thread's "work" consists of sleeping for about a second. Each thread //"works" a little longer, just to make the output more orderly. Thread.Sleep(1000 + padding); Console.WriteLine("Thread {0} releases the semaphore.", num); Console.WriteLine("Thread {0} previous semaphore count: {1}", num, _pool.Release()); }
The Timer class • The Timer class makes it possible to call method with a time interval • The class creates and deleted threads itself
Example: Timer class TimePrinter { static void PrintTime(object state) { Console.WriteLine("Time is: {0}, Param is: {1}", DateTime.Now.ToLongTimeString(), state.ToString()); } static void Main(string[] args) { Console.WriteLine("***** Working with Timer type *****\n"); // Create the delegate for the Timer type. TimerCallback timeCB = new TimerCallback(PrintTime); // Establish timer settings. Timer t = new Timer( timeCB, // The TimerCallback delegate type. "Hi", // Any info to pass into the called method. 0, // Amount of time to wait before starting. 1000); // Interval of time between calls. Console.WriteLine("Hit key to terminate..."); Console.ReadLine(); } }
Timer (2) • What happens if execution of the method takes longer than the interval static int count = 0; static void PrintTime(object state) { int internCount; internCount = Interlocked.Increment(ref count); Console.WriteLine("{2} time. Time is: {0}, Param is: {1}", DateTime.Now.ToLongTimeString(), state.ToString(),internCount); Thread.Sleep(2000); Console.WriteLine("The method is finished {0}",internCount); }
Execution.... Multiple threads runs concurrently
ThreadPool • If you in the previous example writes out the thread id you can see that actually only two threads are created • That is because .Net internal reuses threads created by Timer, asynchronious delegates etc. by using a ThreadPool. • The reason is that it takes ressources to create and delete threads • When you use asynchronious delegates or timers you normaly do not need to think about threads. • But if you need to set a priority or to abort a thread etc. then you can't use ThreadPool • With QueueUserWorkItem(WaitCallback callback) you can use thread from the pool to execute a method
Example: ThreadPool Printer p = new Printer(); WaitCallback workItem = new WaitCallback(PrintTheNumbers); // Queue the method 10 times for (int i = 0; i < 10; i++) { ThreadPool.QueueUserWorkItem(workItem, p); }
Exercises (2 classic examples): • Implement Producer / consumer with Semaphore. • Implement Dining Philosophers, see page 296 in Deitel: Operating Systems.