59
1 UCN 2012 Concurrent programming Concurrent programming Threads – Introduction – Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and the .Net 4 Platform Yazan Diranieh: http://www.diranieh.com/ Joe Albahari: http://www.albahari.com Microsoft: http://msdn.microsoft.com

1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

Embed Size (px)

DESCRIPTION

3 UCN 2012Concurrent programming Source: Diranieh Advantages While there are many advantages to using threads, developers must be aware that threading does have disadvantages as well. For example: –Writing multithreaded programs is tricky. Very tricky in many cases. It is difficult for the human mind to jump between parallel sequences of logic. Always revalidate your logic and test as much as possible (especially on multi-CPU machines). –Keeping track of a large number of threads consumes significant processor time. Having too many threads can have the opposite effect of performance. –Destroying threads is not simple as there could be interact dependencies that must be taken into account before ending a thread.

Citation preview

Page 1: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

1UCN 2012 Concurrent programming

Concurrent programming

• Threads– Introduction– Synchronization

Sources for this presentation:Troelsen: Pro C# 2010 and the .Net 4 PlatformYazan Diranieh: http://www.diranieh.com/Joe Albahari: http://www.albahari.com Microsoft: http://msdn.microsoft.com

Page 2: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

2UCN 2012 Concurrent programming Source: Diranieh

Introduction

• Threads are the basic unit to which an operating system allocates CPU time. Each thread maintains exception handlers, a scheduling priority and a set of structures that the OS uses to save the thread context until it is scheduled.

• The thread context includes all the information that the thread requires to seamlessly resume execution including the thread's set of CPU registers and stack in the address space of the hosting process.

Page 3: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

3UCN 2012 Concurrent programming Source: Diranieh

Advantages

• While there are many advantages to using threads, developers must be aware that threading does have disadvantages as well. For example:– Writing multithreaded programs is tricky. Very tricky in many cases. It

is difficult for the human mind to jump between parallel sequences of logic. Always revalidate your logic and test as much as possible (especially on multi-CPU machines).

– Keeping track of a large number of threads consumes significant processor time. Having too many threads can have the opposite effect of performance.

– Destroying threads is not simple as there could be interact dependencies that must be taken into account before ending a thread. 

Page 4: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

4UCN 2012 Concurrent programming Source: Diranieh

ThreadPool

• In general, using the ThreadPool class is the easiest way to handle multiple requests for relatively short tasks that will not block other threads and when you do not expect any particular ordering of scheduling. However, there are a number of reasons to create your own threads:– You want to control the task's priority. – Your task may run for a long time (and hence block other threads). – You may need to place threads in a Single-Threaded Apartment (all

ThreadPool threads reside in a multi-threaded apartment).  – You need a stable identity for a thread so that you can abort,

suspend or discover by name.

Page 5: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

5UCN 2012 Concurrent programming Source: Diranieh

Problems

• Multiple threads often access the same resource and this creates huge problems in the form of conflicts, deadlocks and race conditions. To avoid these situations, access to shared resources must be controlled or synchronized. Resources that require synchronization often include:– System resources such as communication ports. – Resources shared my multiple processes such as file handles. – Resources of a single application (like global filed) accessed by

multiple threads.

Page 6: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

6UCN 2012 Concurrent programming Source: Diranieh

Working with Threads

• For each thread, the OS allocates the following:– Registers. – A program counter. – A stack and a stack pointer. – Time slot  – Priority. 

Page 7: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

7UCN 2012 Concurrent programming

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

Page 8: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

8UCN 2012 Concurrent programming

Thread states

Page 9: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

9UCN 2012 Concurrent programming

Threads

• System.Threading namespace• Some properties on threads• Creation of threads• Synchronization

– Lock– Monitor– [Syncronization]

• Timer callback• ThreadPool

Page 10: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

10UCN 2012 Concurrent programming

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

Page 11: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

11UCN 2012 Concurrent programming Source: Diranieh

Thread class in System.Threading

• The Thread class provides various methods and properties to control the managed thread

• Note that calling methods on the Thread class can be static or instance methods

Page 12: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

12UCN 2012 Concurrent programming Source: Diranieh

Thread class

• CurrentThreadThread.CurrentThread is a static method that returns an instance of Thread representing the currently running thread. Typically you call this method from the function associated with your thread.

• GetHashCodeThread.GetHashCode is an instance method used to retrieve an ID that uniquely identifies the thread (thread ID). Thread.GetHashCode is guaranteed to return a value that is unique system-wide. If you need to programmatically access the physical thread ID allocated by the OS use the static AppDomain.GetCurrentThreadId method.

• NameThread.Name allows you to assign a human-readable name to the thread. By default, a .NET thread is nameless. Assigning a name to each thread you create is highly desirable as it can be an invaluable piece of information when debugging multi-threaded applications.

Page 13: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

13UCN 2012 Concurrent programming Source: Diranieh

Creating Threads

• To create a new thread, create a new instance of class Thread and associate it with its thread method. The new Thread object will execute the designated thread method on a new thread.

• This new thread will terminate when the thread method terminates.• The thread method can either be static or instance, public or

private on any object.

Page 14: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

14UCN 2012 Concurrent programming Source: Diranieh

Example

void <ThreadFunctionName>();        // Returns void and takes no parameters

You associate a Thread object with a thread function using a dedicated delegate called ThreadStart. This association must be established in Thread's constructor:

Thread thread = new Thread( new ThreadStart(MyThreadFunction) );

The thread is created is in the unstarted state (thread.ThreadState  = ThreadState.Unstarted). To start the thread, simple call Start:

thread.Start();

Page 15: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

15UCN 2012 Concurrent programming Source: Diranieh

Thread Methods

• A thread method can do whatever you want it to do. Typically, however, it will contain some sort of a loop where the thread performs some finite amount of work in each iteration and then checks for some condition, letting it know whether to do another iteration or to terminate:

void MyThreadMethod(){    while <Some condition>        Do work ...}

Page 16: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

16UCN 2012 Concurrent programming

Passing Thread Parameters

• The ThreadStart delegate signature does not allow for any parameters to be passed.

• One way to pass parameters to the thread function is to make the thread function a member function of class whose properties can be used to hold parameter values. The thread function (i.e., member function) can then access properties to retrieve parameter values.

• Another (newer) way is to use the ParameterizedThreadStart delegate, which takes an Object type as parameter.

Page 17: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

17UCN 2012 Concurrent programming Source: Diranieh

ThreadStart use member properties in the class that contains the thread method public class MyThreadClass{    // Data members    string  m_strName;    int     m_nID;

    // Properties    public string Name    {        set { m_strName = value;}        get { return m_strName; }            }    public int ID    {        set { m_nID = value;}        get { return m_nID; }            }

    // Thread function    private void ProcessData()    {        // Get relevant parameters        string name = Name;        int    id   = ID;

        // ,,,

    } }

Page 18: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

18UCN 2012 Concurrent programming

Using parameters the ParameterizedThreadStart delegate• Make a simple class for the parameters. It should only contain

properties.• Instanate an Object of the class, set the parameters and pass it to

the ParameterizedThreadStart delegate.

• This is shown on the following slides.

Page 19: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

19UCN 2012 Concurrent programming

Create a new threadUsing the ParameterizedThreadStart delegate

1. Make a class for objects that contains the parameters2. Make a method that shall be used when starting the thread.

Similar to implementing Start() in Java.3. Make a ParameterizedThreadStart delegate, and use the method as

parameter to the constructor4. Instanstiate a new thread object and use the delegate as the

parameter to the constructor5. Set properties for the thread (name, priority etc.)6. Call theThread.Start() method.

Page 20: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

20UCN 2012 Concurrent programming Source: Troelsen

Create the parameter class (step 1)

using System.Threading; class AddParams { public int a { get; set; } public int b { get; set; }

}con't....

Use as parameters to the thread method: Add (Object obj).

Page 21: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

21UCN 2012 Concurrent programming Source: Troelsen

Create thread with ParameterizedThreadStart (step 2)

using System.Threading;

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 the thread method, therefore the Object

Page 22: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

22UCN 2012 Concurrent programming Source: Troelsen

Create thread with ParameterizedThreadStart (step 3-6) 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

{ a = 10, b = 20 }; //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(); }

Page 23: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

23UCN 2012 Concurrent programming

Properties on the thread

• You can get some information about the threads by invoking properties on the Thread object.

• See example on next slide

Page 24: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

24UCN 2012 Concurrent programming Source: Troelsen

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);

Page 25: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

25UCN 2012 Concurrent programming Source: Diranieh

Blocking Threads

• Class Thread provides several methods to block the execution of the associated thread.

• These include suspending the threading, sleeping, and waiting for another thread to terminate.

• Sleeping– Thread.Sleep is used to put the thread to sleep for a specified amount of

time. And because it is a static method, only the thread itself can put itself to sleep.

• Spinning while waiting– Class Thread provides another sleep-like operation called

Thread.SpinWait. – The static Thread.SpinWait causes the calling thread to wait the number

of iterations specified and the thread is never added to the queue of waiting threads. As a result, the thread is put to sleep without effectively relinquishing the remainder of its CPU slot

– Thread.SpinWait does not replace Thread.Sleep but is intended as an advanced optimization technique. For example, if you know your thread is waiting for a resource that will be available very soon, then it is possibly more efficient to spin and wait rather than using Thread.Sleep.

Page 26: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

26UCN 2012 Concurrent programming

• Joining – Thread.Join method allows the calling thread to block until

another thread terminates.

public void WaitForProcessingThreadToDie(Thread ProcessingThread){    // Wait for the ProcessingThread thread to die.

    ProcessingThread.Join();

    // ProcessingThread thread has died. Perform appropriate actions    ...}

• Suspending & Resuming– Thread.Suspend and Thread.Resume methods are used to suspend

and resume threads.– Are deprecated due to security reasons.

Page 27: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

27UCN 2012 Concurrent programming Source: Diranieh

Synchronization

• Suppose we have to implement a function to handle withdrawals from a bank account:

withdraw (account, amount) {balance = get_balance(account);balance = balance – amount;put_balance(account, balance);return balance;

}

• Now suppose that you and your significant other share a bank account with a balance of $1000.

• Then you each go to separate ATM machines and simultaneously withdraw $100 from the account.

Page 28: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

28UCN 2012 Concurrent programming Source: Diranieh

• We’ll represent the situation by creating a separate thread for each person to do the withdrawals

withdraw (account, amount) {balance = get_balance(account);balance = balance – amount;put_balance(account, balance);return balance;}

withdraw (account, amount) {balance = get_balance(account);balance = balance – amount;put_balance(account, balance);return balance;

}– These threads run in the same bank process:– What’s the problem with this implementation?– Think about potential schedules of these two threads

Page 29: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

29UCN 2012 Concurrent programming Source: Diranieh

• The problem is that the execution of the two threads can be interleaved:

balance = get_balance(account);balance = balance – amount;balance = get_balance(account);balance = balance – amount;put_balance(account, balance);put_balance(account, balance);

• What is the balance of the account now?• This is known as a race condition• Each thread is “racing” to put_balance() before the other

Page 30: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

30UCN 2012 Concurrent programming Source: Diranieh

Mutual Exclusion

• One way to ensure who wins the race is to only let one thread “compete”; this is called mutual exclusion

• Code that uses mutual exclusion to synchronize its execution is called a critical section

• Only one thread at a time can execute in the critical section• All other threads are forced to wait on entry• When a thread leaves a critical section, another can enter

withdraw (account, amount) {balance = get_balance(account);balance = balance – amount; crictical sectionput_balance(account, balance);

return balance;}

Page 31: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

31UCN 2012 Concurrent programming

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.

Page 32: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

32UCN 2012 Concurrent programming

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(); } } }

Page 33: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

33UCN 2012 Concurrent programming

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(); }

Page 34: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

34UCN 2012 Concurrent programming

Execution with lock...

Page 35: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

35UCN 2012 Concurrent programming

Execution without lock....

Page 36: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

36UCN 2012 Concurrent programming

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);

} }

Page 37: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

37UCN 2012 Concurrent programming

Execution

Page 38: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

38UCN 2012 Concurrent programming Source: Albahari

[Synchronization]Source: http://www.albahari.com/threading/part2.aspx

• An alternative to locking manually is to lock declaratively. • By deriving from ContextBoundObject and applying the

[Synchronization] attribute, you instruct the CLR to apply locking automatically.

• The CLR ensures that only one thread can execute code in safeInstance at a time. It does this by creating a single synchronizing object — and locking it around every call to each of safeInstance's methods or properties.

• The scope of the lock — in this case, the safeInstance object — is called a synchronization context.

Automatic synchronization cannot be used to protect static type members, nor classes not derived from ContextBoundObject (for instance, a Windows Form).

Page 39: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

39UCN 2012 Concurrent programming Source: Albahari

[Synchronization]Source: http://www.albahari.com/threading/part2.aspx

• So, how does this work? A clue is in the Synchronization attribute's namespace: System.Runtime.Remoting.Contexts.

• A ContextBoundObject can be thought of as a “remote” object, meaning all method calls are intercepted. To make this interception possible, when we instantiate AutoLock, the CLR actually returns a proxy — an object with the same methods and properties of an AutoLock object, which acts as an intermediary. It's via this intermediary that the automatic locking takes place. Overall, the interception adds around a microsecond to each method call.

Page 40: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

40UCN 2012 Concurrent programming Source: Albahari

using System;using System.Threading;using System.Runtime.Remoting.Contexts;

[Synchronization]public class AutoLock { public void Demo() { Console.Write("Start..."); Thread.Sleep(1000); Console.WriteLine("end"); } public void Test() { new Thread(Demo).Start(); new Thread(Demo).Start(); new Thread(Demo).Start(); } public static void Main() { new AutoLock().Test(); }}

Page 41: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

41UCN 2012 Concurrent programming Source: Albahari

using System;using System.Threading;using System.Runtime.Remoting.Contexts;

[Synchronization]public class AutoLock { public void Demo() { Console.Write("Start..."); Thread.Sleep(1000); Console.WriteLine("end"); } public void Test() { new Thread(Demo).Start(); new Thread(Demo).Start(); new Thread(Demo).Start(); Console.ReadLine(); } public static void Main() { new AutoLock().Test(); }}

This example looks the same.But what happens when it runs?

Page 42: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

42UCN 2012 Concurrent programming Source: Albahari

What happened?

• Notice that we've sneaked in a Console.ReadLine statement.• Because only one thread can execute code at a time in an object of

this class, the three new threads will remain blocked at the Demo method until the Testmethod finishes — which requires the ReadLine to complete.

• Hence we end up with the same result as before, but only after pressing the Enter key.

• This is a thread-safety hammer almost big enough to preclude any useful multithreading within a class!

Page 43: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

43UCN 2012 Concurrent programming Source: Albahari

• Do the first exercise now.

Page 44: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

44UCN 2012 Concurrent programming Source: Albahari

Mutex

• A Mutex is like a C# lock, but it can work across multiple processes, if it got a name.

• In other words, Mutex can be computer-wide as well as application-wide.

• With a Mutex class, you call the WaitOne method to lock and ReleaseMutexto unlock.

• Closing or disposing a Mutex automatically releases it. Just as with the lock statement, a Mutex can be released only from the same thread that obtained it.

• Acquiring and releasing an uncontended Mutex takes a few microseconds — about 50 times slower than a lock.

• If running under Terminal Services, a computer-wide Mutex is ordinarily visible only to applications in the same terminal server session. To make it visible to all terminal server sessions, prefix its name with Global\.

Page 45: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

45UCN 2012 Concurrent programming Source: Albahari

• A common use for a cross-process Mutexis to ensure that only one instance of a program can run at a time. Here’s how it’s done

using System;using System.Threading;class OneAtATimePlease { static void Main() { // Naming a Mutex makes it available computer-wide. Use a name that's // unique to your company and application (e.g., include your URL). using (var mutex = new Mutex(false, "oreilly.com OneAtATimeDemo")) { // Wait a few seconds if contended, in case another instance // of the program is still in the process of shutting down. if (!mutex.WaitOne(TimeSpan.FromSeconds(3), false)) { Console.WriteLine("Another app instance is running. Bye!"); return; } RunProgram(); } } static void RunProgram() { Console.WriteLine("Running. Press Enter to exit"); Console.ReadLine(); }}

Page 46: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

46UCN 2012 Concurrent programming Source: Albahari

Semaphore

• A semaphore is like a nightclub: it has a certain capacity, enforced by a bouncer. Once it’s full, no more people can enter, and a queue builds up outside. Then, for each person that leaves, one person enters from the head of the queue. The constructor requires a minimum of two arguments: the number of places currently available in the nightclub and the club’s total capacity.

• A semaphore with a capacity of one is similar to a Mutex or lock, except that the semaphore has no “owner” — it’s thread-agnostic. Any thread can call Release on a Semaphore, whereas with Mutex and lock, only the thread that obtained the lock can release it.

Page 47: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

47UCN 2012 Concurrent programming Source: Albahari

Semaphore

• There are two functionally similar versions of this class: Semaphore and SemaphoreSlim.

• The latter was introduced in Framework 4.0 and has been optimized to meet the low-latency demands of parallel programming.

• It’s also useful in traditional multithreading because it lets you specify a cancellation token when waiting.

• It cannot, however, be used for interprocess signaling. • Semaphore incurs about 1 microsecond in calling WaitOne or

Release; SemaphoreSlim incurs about a quarter of that• Semaphores can be useful in limiting concurrency — preventing too

many threads from executing a particular piece of code at once. • In the following example, five threads try to enter a nightclub that

allows only three threads in at once

Page 48: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

48UCN 2012 Concurrent programming Source: Albahari

Example: SemaphoreSlim

using System.Threading;using System;class TheClub // No door lists!{ static SemaphoreSlim _sem = new SemaphoreSlim(3);// Capacity of 3

static void Main() { for (int i = 1; i <= 5; i++) new Thread(Enter).Start(i); Console.ReadLine(); } static void Enter(object id) { Console.WriteLine(id + " wants to enter"); _sem.Wait(); Console.WriteLine(id + " is in!"); // Only three threads Thread.Sleep(1000 * (int)id); // can be here at Console.WriteLine(id + " is leaving"); // a time. _sem.Release(); }}

Notice this compact coding style

Page 49: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

49UCN 2012 Concurrent programming Source: Troelsen

Example: Semaphorepublic 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 // Release the 3 tokens that Main holds Console.WriteLine("Main thread calls Release(3)."); _pool.Release(3); Console.WriteLine("Main thread exits."); Console.ReadLine(); }

Page 50: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

50UCN 2012 Concurrent programming Source: Troelsen

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()); }

Page 51: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

51UCN 2012 Concurrent programming

Execution....

Page 52: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

52UCN 2012 Concurrent programming

The Timer class

• The Timer class makes it possible to call method with a time interval

• The class creates and deleted threads itself

Page 53: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

53UCN 2012 Concurrent programming Source: Troelsen

Example: Timerclass 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();}}

Page 54: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

54UCN 2012 Concurrent programming

Execution...

Page 55: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

55UCN 2012 Concurrent programming

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);

}

Page 56: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

56UCN 2012 Concurrent programming

Execution....

Multiple threads runs concurrently

Page 57: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

57UCN 2012 Concurrent programming

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

Page 58: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

58UCN 2012 Concurrent programming

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); }

Page 59: 1 UCN 2012Concurrent programming Concurrent programming Threads Introduction Synchronization Sources for this presentation: Troelsen: Pro C# 2010 and

59UCN 2012 Concurrent programming

Exercises (2 classic examples):

• Do the getting started: Follow the slides • Implement Producer / consumer with Semaphore.• Implement Dining Philosophers, see page 296 in Deitel: Operating

Systems.