This thread terminates when Main returns. However, auxiliary threads can be created and used to execute code in parallel with the primary thread.. 11.1 Threading in C# and .NET Work
Trang 3Roadmap
11.1 Threading in C# and NET
11.2 Synchronizing Work Between Threads
11.3 Using ThreadPool
3
Trang 4 This thread terminates when Main returns.
However, auxiliary threads can be created and used to execute code in parallel with the primary thread These threads are often called worker threads
Trang 511.1 Threading in C# and NET
Worker threads can be used to perform the following
without tying up the primary thread
• Time-consuming tasks.
• Or time critical tasks
For example, worker threads are often used
• In server applications to fulfill incoming requests without waiting for the previous request to be completed
• To perform "background" tasks in desktop applications so that the main thread which drives user interface elements remains responsive to user actions.
5
Trang 6• And race conditions
Multiple threads are best for tasks that require different resources
Trang 7States of a Thread
Trang 8Microsoft
Trang 9Create and Terminate Threads
The following example will demonstrate:
• How an auxiliary or worker thread can be created and used to perform processing in parallel with the primary thread
• Besides, making one thread wait for another and gracefully terminating a thread
Trang 10using System;
using System.Threading;
public class Worker
{
// This method will be called when the thread is started.
public void DoWork()
// Volatile is used as hint to the compiler that this data
// member will be accessed by multiple threads.
private volatile bool _shouldStop;
}
Example
executed by worker thread.
It requests work thread to stop
safely access this member from multiple threads.
Trang 11Worker workerObject = new Worker();
Thread workerThread = new
// Use the Join method to block the current thread
// until the object's thread terminates.
Put the main thread to sleep for 1 millisecond
to allow the worker thread to
do some work:
Trang 1211.2 Synchronizing Work Between
Threads
12
Need synchronization primitives
• Way to ensure that only one thread executes code in a region at once
• Called “critical section”
C# provides (mostly in System.Threading)
Trang 13Threading model: lock
Basic idea: each object has a lock
• lock prevents more than one thread from entering
• forces sequential order
What should we lock on?
• for instance variables: this
• for globals and statics: typeof(container)
• something that will be same for all threads that access this shared memory
public int Increment(ref int x)
{
lock(this) return ++x;
}
Trang 14Threading model: Monitor
Monitors provide synchronization construct
• entry waits on a queue
• waiting lets a new thread enter
Monitor.Enter and Monitor.Exit
• same semantics as the lock construct
Trang 15Threading model: Monitor
Gets a lock on the object
• Cannot be used on value types: why not?
• Monitor.Enter/Monitor.Exit
• enter/exit the monitor for a given object
Trang 16Threading model: Monitor
• Monitor.Wait
• wait on a given object
• must be inside a monitor for that object
• signal-delayed semantics
• Monitor.Pulse/Monitor.PulseAll
• some thread(s) can be released to try the monitor
Trang 17Threading model: Interrupt
Sometimes need to wake up a thread
• eg if UI cancelled
• eg if event no longer needed
Standard OO way: exceptions
• Interrupt causes thread to throw ThreadInterruptedException
• only on Wait or Sleep
• Allows cleanup of invariants
Trang 18Semaphore
What does it operate ?
• Allow a countable number of threads to acquire a
resource simultaneously
• The semaphore count is decremented when a thread enters the semaphore via WaitOne or any of the other Wait methods
• the count is incremented when an owning thread calls Release
• If a thread attempts to enter the semaphore when the count is zero, it will block until another thread calls Release
Trang 19Remark
Create semaphore without a name end up with a local semaphore
• Usefully within the same process
• Need to synchronize access across multiple
processes for security reasons.
⇒
Trang 20Other synchro classes
Abort
• throws exception immediately
• difficult to clean up: Why?
• usually too draconian
Mutex and other synchronization
• good for interacting with Windows
• but stick with lock and Monitor, normally
Trang 21private static Mutex mut = new Mutex();
private const int numIterations = 1;
private const int numThreads = 3;
static void Main()
Create the threads that will use the protected resource.
Trang 22private static void MyThreadProc()
// Place code to access non-reentrant resources here.
// Simulate some work.
This method represents
a resource that must be
synchronized
so that only one thread at a time can
enter.
Trang 2311.3 Using ThreadPool
A thread pool is a collection of threads that
• Can be used to perform several tasks in the
background
• Leaves the primary thread free to perform other tasks asynchronously
When having an incoming request:
• It is assigned to a thread from the thread pool
• It can be processed asynchronously without tying up the primary thread or delaying the processing of
subsequent requests
A thread in the pool can be reused
• To avoid the cost of creating a new thread for each task
Trang 24• takes a WaitCallback delegate
Good for large amounts of parallel work
• eg N-Body problem
• automatically scales to number of processors
• “embarrasingly parallel” problems
Trang 25using System;
using System.Threading;
public class Fibonacci {
public Fibonacci(int n, ManualResetEvent doneEvent) {
_n = n;
_doneEvent = doneEvent;
}
public void ThreadPoolCallback( Object threadContext) {
int threadIndex = (int)threadContext;
Console.WriteLine( "thread {0} started ", threadIndex); _fibOfN = Calculate(_n);
Console.WriteLine( "thread {0} result calculated ",
public int FibOfN { get { return _fibOfN; } }
private int _fibOfN;
private ManualResetEvent _doneEvent;
}
Example
Wrapper method for use with thread pool
Recursive method that calculates the Nth Fibonacci number
Trang 26public class ThreadPoolExample {
static void Main() {
const int FibonacciCalculations = 10;
// One event is used for each Fibonacci object
for (int i = 0; i < FibonacciCalculations; i++) {
doneEvents[i] = new ManualResetEvent( false);
Fibonacci f = new Fibonacci(r.Next(20, 40),
Console.WriteLine( "All calculations are complete.");
// Display the results
ThreadPool:
Wait for all threads in pool to calculation
Trang 27Timers
Another entry point into the thread pool is via Timer
objects in the System.Threading namespace
We can arrange for the thread pool to call a delegate at
a specific time as well as at regular intervals
An example of how to use a Timer object:
Trang 28using System;
using System.Threading;
public class EntryPoint {
private static void TimerProc(object state) {
Thread.CurrentThread.GetHashCode());
Thread.Sleep(3000);
}
static void Main() {
Trang 30Sumary
In this chapter we have seen:
• The intricacies of managed threads in the NET
• Threading always adds complexity to applications such as difference to implement