net mobile application development concurrency in distributed clients
Post on 21-Dec-2015
227 views
TRANSCRIPT
.NET Mobile Application Development
Concurrency in Distributed Clients
Introduction
Concurrency occurs in all distributed systems Controlling concurrency is essentially to developing
scalable, correct distributed applications
In this session and the next we will consider > Multi-threading and concurrency
> Concurrency in distributed clients
> Concurrency control mechanisms
Concurrency in Distributed Applications
Distributed applications are inherently concurrent> Services have to deal with multiple simultaneous clients in a scalable
manner
> Clients may need to perform multiple simultaneous activities
Accept user input and use services
Concurrency needs to be used and managed correctly to avoid
> Performance penalties
> Incorrect operation and sequencing of activities
Concurrency in Distributed Clients
Concurrency is mainly used in distributed clients to overcome latencies resulting from distributed interactions
This has several benefits> Increased client performance
Client can perform other activities / processing whilst remote interactions proceed
> Increased client responsiveness and improved user experience
User interface does not freeze when remote interactions or lengthy computations occur
Application responds to user input in a timely manner
Multithreading
Thread> An independent unit of program execution
Multithreaded program> Multiple threads execute simultaneously
Threads multiplexed onto available CPU’s using timeslicing Context switch incurs (minor) overhead
> Threads exist in the same process and share common address space
Multithreading > can improve performance only when there is an operation with some latency
the longer the delay, the greater the potential performance benefit from using threads
> will not improve performance if threads are competing for finite (e.g. CPU) resources; multithreading will actually result in worse performance
Threading Issues
Multithreading can improve performance Multithreading will introduce
> additional complexity> unusual errors that are difficult to detect, replicate and debug > additional overhead; OS must manage all the threads
Getting threading right is difficult; need to> use synchronization and locking to ensure correct interleaving of thread
operations and interactions> balance potential improvements from threading against additional
overheads (number of threads)> avoid deadlock, livelock, race conditions, etc caused by incorrect /
insufficient / too much synchronization
Threading in .NET
Can use threads in .NET by> Using .NET types with built-in threading support
Types that support asynchronous operation (i.e. has Begin? and End? methods)
Windows forms types through the Invoke() method> Manually creating and manipulating threads using the System.Threading.Thread type
Using Asynchronous Delegates
A delegate is> a type-safe pointer to a method (function pointer)
> an instance of the Delegate type
Delegate type has two important methods> BeginInvoke()
invokes the method referred to by the delegate on a separate thread
immediately returns an IAsyncResult instance and allows calling thread to continue
> EndInvoke()
allows retrieval of results from a method invoked earlier using BeginInvoke()
needs to be given IAsyncResult instance returned by BeginInvoke()
Asynchronous Delegate Example
delegate int MyDelegate(int i, int j);
class Program { public static void Main() {
Maths m = new Maths();
// Create the delegate - note that BeginInvoke always takes 2 extra parametersMyDelegate dlgt = new MyDelegate(m.Add);// Asynchronosly invoke itIAsyncResult iar = dlgt.BeginInvoke(2, 2, null, null);
// Do something else whilst call progresses
// Wait for async method to complete and retrieve the results int result = dlgt.EndInvoke(iar);
}}
class Maths {public int Add(int a, int b) {
return a+b;}
}
Criticisms•EndInvoke() call blocks if method invoked by delegate not yet completed•Can poll for completion using the IAsyncResult instance•Neither option is good
Using Callbacks
Callback > method called when an asynchronously invoked delegate completes its
operation Callbacks
> eliminate inefficient polling > simplify coding
Callback method> signature must match System.AsyncCallback delegate type > AsyncCallback instance referencing desired callback method must be
passed to BeginInvoke()> callback is passed an IAsyncResult object when it is invoked
use this to call EndInvoke() and retrieve results
Asynchronous Callback Example
delegate int MyDelegate(int i, int j);
class Program{ static MyDelegate dlgt;
public static void Main() {Maths m = new Maths();AsyncCallback cdlgt = new AsyncCallback(MyCallback);dlgt = new MyDelegate(m.Add);
// Penultimate BeginInvoke() parameter is callback delegateIAsyncResult iar = dlgt.BeginInvoke(2, 2, cdlgt, null);Console.ReadLine(); // Do something else
}
public static void MyCallback(IAsyncResult iar) {int result = dlgt.EndInvoke(iar); // Use IAsyncResult instance to retrieve the results
}}
class Maths {public int Add(int a, int b){ return a+b; }
}
NOTE: •Callback method executes on yet another thread
Advantages of Asynchronous Invocation
Implicitly using threads by using asynchronous invocation has several advantages
> environment takes care of creating and managing all threads for us
> no need for explicit concurrency control operations
> improves performance by enabling long-running tasks to be started without stalling application
Asynchronous invocation not suitable for> code which needs to communicate between threads
> applications which need to prioritize threads
> this requires manual thread creation
Creating .NET Threads
Threads are created by> declaring a method which will be the body of the thread
must be of return type void and accept no parameters can call any other methods
> creating a ThreadStart delegate instance which refers to this method > creating a new Thread object, passing it the delegate> calling Thread.Start()
System.Threading.Thread > is the primary type used for managing threads > allows threads to be created, started, stopped, suspended, resumed,
joined, delayed, etc
Custom Threading Example
class Program{ public static void Main() {
// Create the threadsThread tA = new Thread(new ThreadStart(TaskA));Thread tB = new Thread(new ThreadStart(TaskB));tA.Start(); // Start the threadstB.Start();Console.ReadLine(); // Pause until user presses key
}
private static void TaskA() {for (int i = 0; i < 10; i++) {
Console.WriteLine("Task A at: "+i);WasteTime(1000); }
}
private static void TaskB() {for (int i = 0; i < 10; i++) {
Console.WriteLine("Task B at: "+i);WasteTime(1000); }
}}
Thread Priorities
Threads are selected for execution based on their priority> highest priority execute first, lowest priority last
All threads created equally with default normal priority> priority can be adjusted via Thread.Priority property
> five relative priority levels supported
Lowest, Below Normal, Normal, Above Normal, Highest
Setting thread priorities correctly is important> giving a thread too high a priority can lead to starvation of other threads
Thread Priority Example
class Program{ public static void Main() {
Thread tA = new Thread(new ThreadStart(TaskA));Thread tB = new Thread(new ThreadStart(TaskB));
tA.Priority = ThreadPriority.AboveNormal; tB.Priority = ThreadPriority.Normal;tA.Start(); tB.Start(); // Start the threadsConsole.ReadLine(); // Pause until user presses key
}
private static void TaskA() {for (int i = 0; i < 10; i++) {
Console.WriteLine("Task A at: "+i);WasteTime(1); }
}
private static void TaskB() {for (int i = 0; i < 10; i++) {
Console.WriteLine("Task B at: "+i);WasteTime(1); }
}}
Threaded Clients
Any operation which will take a long time to complete or adversely affect application responsiveness is a good candidate for executing on a separate thread
e.g. Windows Media Player 9> Info Center View takes time to retrieve data from the Internet> executing this on separate thread from user interface allows user to
control playback in the meantime> when data is returned from Internet, UI can be appropriately
updated
User Interfaces in .NET Threaded Clients
Windows Forms controls in a .NET application > are not thread safe> can only be safely operated upon by the thread which owns them
Consider the Windows Media Player example with a thread which fetches data from the Internet. This thread
> is separate from the UI thread> should not update the application’s UI as it is not the owner of the UI
controls
Win Forms and Threading
Windows.Forms.Control base class provides an Invoke() method which is passed a delegate to another method
> Delegate must be of type MethodInvoker
Delegated method acts as a callback used to update the relevant control
Calling Invoke() causes the delegated update method to be safely invoked on the User Interface thread which owns the control
WinForms Threading Example
Simple Form application with two threads> UI thread created by Application.Run()> separate thread used to periodically increments counter> button controls operation of counter thread
UIUpdater() displays latest count value in lblCount Label
Counter thread > creates delegate to UIUpdater() > calls lblCount.Invoke() with this delegate each time it wishes
to update the count value in the UI
Concurrency Control
Two key aspects to concurrency control Mutual exclusion
> Preventing object / resource from being accessed by more than one thread at once
> Needed to prevent corruption of state in presence of multiple client updates
> Implemented through locking
Synchronization> Imposes order on interleaving of operations of multiple threads (usually for
correctness)
> Implemented using semaphores, condition variables or monitors
Condition Synchronization
Needed when a thread wishes to perform an operation which can only sensibly(safely) be performed if another thread has itself taken some other action or is in some defined state
Example : A bounded buffer has 2 condition synchronization
> producer thread must not attempt to put data in buffer if it is full
> consumer thread must not attempt to get data from buffer if it is empty
> Is mutual exclusion necessary?
Locks and Mutual Exclusion
Critical Section - a sequence of statements that appear to execute indivisibly
Mutual Exclusion - synchronization required to protect a critical section
Locks - implement mutual exclusion and guard critical sections
> Code construct which marks a critical section of code that must be executed under mutual exclusion
Locking
In an OO environment, every object has an associated lock
Lock construct specifies the object on which the lock should be obtained
First thread to execute the lock statement will be granted the lock and can execute protected section of code
> Whilst first thread has the lock, any other threads executing the lock statement will block until lock is released. Waiting threads will then compete for the lock.
Example: Locking in C#
int Withdraw(int amount)
{
lock (this)
{
if (balance >= amount) {
Console.WriteLine("Balance before Withdrawal : " + balance);
Console.WriteLine("Amount to Withdraw : -" + amount);
balance = balance - amount;
Console.WriteLine("Balance after Withdrawal : " + balance);
return amount;
}
else {
return 0; // transaction rejected
}
}
}
Locking - Disadvantages
Locking is essential to preventing conflicting updates but can adversely affect performance
If scope of lock is too great> forces some threads to wait
> decreases potential concurrency and throughput / performance
If scope of lock is too small> forces reacquisition of locks, leading increased lock contention and
reduced throughput / performance
> can result in difficult-to-debug race conditions
Advanced Locking
Mutual exclusion> not needed if all threads are reading values> needed if at least one thread is writing values
ReaderWriter lock > allows concurrent read access for multiple threads, or > write access for a single thread > uses separate locks for readers and writers; clients must specify
which lock they want
Advanced Locking Example
ReaderWriterLock rwl = new ReaderWriterLock();
void ReadFromResource(int timeOut) { try { rwl.AcquireReaderLock(timeOut); try {
/ Safe for this thread to read from // the shared resource. } finally {
// Ensure that the lock is released. rwl.ReleaseReaderLock(); } } catch (ApplicationException) { // The reader request timed out. }}
void WriteToResource(int timeOut) { try { rwl.AcquireWriterLock(timeOut); try { // It is safe for this thread to read // or write from the shared resource. } finally {
// Ensure that the lock is released. rwl.ReleaseWriterLock(); } } catch (ApplicationException) { // The writer lock request timed out. }}
Monitors
Monitor > code construct that provides both mutual exclusion and condition
synchronization> acts like a ‘smart’ lock
Thread enters the monitor and attempts to acquire lock
> if successful, thread executes under mutual exclusion; thread frees lock when finished
> if unsuccessful, thread blocks until monitor is available
Monitors: Condition Synchronisation
When inside a monitor, condition variables can be used
> Thread can Wait() on condition variable thread blocks and releases lock, freeing monitor to other
threads when condition becomes true, thread unblocks, reacquires lock
and executes under mutual exclusion> Thread can Signal() a condition variable
notifies waiting threads that condition is true teleases lock, freeing monitor to other threads
.NET Monitors Example
public class MyClass{private object x;
public void DoSomething() { Monitor.Enter(x); try { // Code that needs protected by the monitor.
// Monitor.Wait and Monitor.Pulse can be// used in here
} finally { // Ensure that you exit Monitor.
Monitor.Exit(x); }}
Common Concurrency Problems
Two common problems Deadlock
> A situation where two or more threads are unable to proceed because each is waiting for the others to do something
> Avoid by always acquiring / releasing locks in the same order ensuring that all Wait()’s have a matching Signal()
Race Conditions> Anomalous behaviour due to unexpected critical dependence on the relative
ordering of operations> Can occur is scope of locks is too small and some code left outside critical sections
These problems are> Easy to unwittingly introduce> Difficult to detect and remove
In this session we have discussed> The role of concurrency in distributed clients
> Multi-threading and thread management in .NET
> Asynchronous invocation and callback
> Locks, monitors and performance
> Alternative thread coordination mechanisms
Summary
Reading and Resources
Reading Coulouris, Dollimore & Kindberg, Distributed Systems:
Concepts and Design, 3rd Edition, Addison-Wesley, 2001Chapter 12, pp 465 – 514
MacDonald, Microsoft .NET Distributed Applications: Integrating XML Web Services and .NET Remoting, Microsoft Press, 2003
Chapter 6, pp 175 – 220