Download presentation
Presentation is loading. Please wait.
1
Threading Lecture 11 M. Ipalakova
2
Overview (1) Why to use? To allow an application to perform a task and continue to respond to user input To perform multiple tasks simultaneously To improve the performance of processor-intensive tasks on computers with multiple processors or cores A thread is a unit of execution within a process A single process can have multiple threads (multithreaded)
3
Overview (2) A C# client program (Console, WPF, or Windows Forms) starts in a single thread created automatically by the CLR and operating system (the “main” thread), and is made multithreaded by creating additional threads Namespace System.Threading
4
Drawbacks If a computer has multiple processors and you split processing into two threads, you won’t see a 100 percent performance improvement Writing multithreaded code is quite complex Troubleshooting is complicated, too Using multiple threads consumes more memory and requires some processor overhead, so performance can actually be reduced in some circumstances
5
Example (1) class ThreadTest { static void Main()
Thread t = new Thread (WriteY); // Kick off a new thread t.Start(); // running WriteY() // Simultaneously, do something on the main thread for (int i = 0; i < 1000; i++) Console.Write ("x"); } static void WriteY() Console.Write ("y");
6
Overview (3) Once started, a thread’s IsAlive property returns true, until the point where the thread ends Once ended, a thread cannot restart
7
Local Variables in Threads
The CLR assigns each thread its own memory stack so that local variables are kept separate static void Main() { // Call Go() on a new thread new Thread (Go).Start(); // Call Go() on the main thread Go(); } static void Go() // Declare and use a local variable - 'cycles' for (int cycles = 0; cycles < 5; cycles++) Console.Write ('?');
8
Threads share data if they have a common reference to the same object instance
class ThreadTest { bool done; static void Main() { // Create a common instance ThreadTest tt = new ThreadTest(); new Thread (tt.Go).Start(); tt.Go(); } // Note that Go is now an instance method void Go() if (!done) { done = true; Console.WriteLine ("Done"); }
9
Method Join static void Main() { Thread t = new Thread (Go);
t.Start(); t.Join(); Console.WriteLine ("Thread t has ended!"); } static void Go() for (int i = 0; i < 1000; i++) Console.Write ("y");
10
Method Sleep Thread.Sleep pauses the current thread for a specified period: Thread.Sleep (TimeSpan.FromHours (1)); // sleep for 1 hour Thread.Sleep (500); // sleep for 500 milliseconds While waiting on a Sleep or Join, a thread is blocked and so does not consume CPU resources
11
How Threading Works Multithreading is managed internally by a thread scheduler, which is a function of the operating system It ensures all active threads are allocated appropriate execution time It ensues that threads that are waiting or blocked do not consume CPU time
12
How Threading Works On a single-processor computer, a thread scheduler performs timeslicing – rapidly switching execution between each of the active threads On a multi-processor computer, multithreading is implemented with a mixture of time-slicing and genuine concurrency Time-slicing is needed, because of the operating system’s need to service its own threads – as well as those of other applications
13
Threads vs. Processes A thread is analogous to the operating system process in which your application runs Processes run in parallel on a computer Threads run in parallel within a single process Processes are fully isolated from each other Threads have just a limited degree of isolation (threads share (heap) memory with other threads running in the same application)
14
Threading’s Uses Maintaining a responsive user interface
Making efficient use of an otherwise blocked CPU Parallel programming Allowing requests to be processed simultaneously
15
Naming Threads Each thread has a Name property
You can set a thread’s name just once Attempts to change it later will throw an exception The static Thread.CurrentThread property gives you the currently executing thread In the following example, we set the main thread’s name
16
Naming Threads Example
class ThreadNaming { static void Main() Thread.CurrentThread.Name = "main"; Thread worker = new Thread (Go); worker.Name = "worker"; worker.Start(); Go(); } static void Go() Console.WriteLine ("Hello from " Thread.CurrentThread.Name);
17
Thread Priorities Thread priority controls how the operating system schedules time to a thread Threads with higher priorities run before threads with lower priorities Before starting a thread, you can set the Thread.Priority property using the ThreadPriority enumeration Highest AboveNormal Normal BelowNormal Lowest By default, threads and applications run with Normal priority
18
Naming Threads Example (2)
class ThreadNaming { static void Main() Thread.CurrentThread.Name = "main"; Thread worker = new Thread (Go); worker.Name = "worker"; worker.Priority = ThreadPriority.BelowNormal; worker.Start(); Go(); } static void Go() Console.WriteLine ("Hello from " Thread.CurrentThread.Name); }}
19
Starting and Stopping Threads
Thread.Start method Thread.Abort method to terminate the thread Catch an exception of type ThreadAbortException to allow the thread to respond to being aborted Thread.Suspend method Thread.Resume method to resume a thread that has been suspended (Example 1)
20
Thread State Unstarted. The initial state before a thread is started
Running. The thread is active and executing, typically as a result of another thread calling Thread.Start Stopped. The thread has stopped WaitSleepJoin. The thread is waiting for another thread to complete. Typically this happens after calling Thread.Join on another thread SuspendRequested. The thread is currently responding to a Thread.Suspend request Suspended. The thread has been suspended because another thread called Thread.Suspend AbortRequested. The thread is currently responding to a Thread.Abort request Aborted. The thread has been stopped because another thread called Thread.Abort
21
Thread State You can check a thread’s state using the Thread.ThreadState property
22
Foreground and Background Threads
By default, threads you create explicitly (using Thread class constructor) are foreground threads So long as the foreground thread is active, the application continues to run Background threads are cancelled as soon as the foreground thread stops. Use the Thread.CurrentThread.IsBackground boolean property to determine whether the current thread is foreground or background
23
Thread Pooling A thread pool is a collection of threads that can be used to perform several tasks in the background. This leaves the primary thread free to perform other tasks asynchronously Thread pools are often employed in server applications. Each incoming request is assigned to a thread from the thread pool Once a thread in the pool completes its task, it is returned to a queue of waiting threads, where it can be reused Thread pools typically have a maximum number of threads (that can be changed). If all the threads are busy, additional tasks are put in queue until they can be serviced as threads become available Use the System.Threading.ThreadPool class to run methods in background threads
24
Thread Pooling Example 1
static void Main(string[] args) { // Queue the task. ThreadPool.QueueUserWorkItem(ThreadProc); Console.WriteLine("Main thread does some work, then sleeps."); Thread.Sleep(1000); Console.WriteLine("Main thread exits."); } // This thread procedure performs the task. static void ThreadProc(Object stateInfo) Console.WriteLine("Hello from the thread pool.");
25
Thread Pooling Example 2
static void Main(string[] args) { string state = "Hello, world!"; ThreadPool.QueueUserWorkItem(ThreadProc, state); Console.WriteLine("Main thread does some work, then sleeps."); Thread.Sleep(1000); Console.WriteLine("Main thread exits."); } // You must manually cast from the Object class in C# static void ThreadProc(Object stateInfo) string state = (string)stateInfo; Console.WriteLine("Hello from the thread pool: " + state);
26
Thread Pooling Example 3
static void Main(string[] args) { ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 1"); ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 2"); ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 3"); ThreadPool.QueueUserWorkItem(ThreadProc, "Thread 4"); Console.WriteLine("Main thread does some work, then sleeps."); Thread.Sleep(1000); Console.WriteLine("Main thread exits."); } static void ThreadProc(Object stateInfo) string state = (string)stateInfo; Console.WriteLine("Hello from the thread pool: " + state);
27
Synchronization Essentials
Synchronization – coordinating the actions of threads for a predictable outcome Synchronization is important when threads access the same data Synchronization constructs can be divided into four categories: Simple blocking methods (Sleep, Join methods) Locking constructs. These limit the number of threads that can perform some activity or execute a section of code at a time. (Monitor.Enter/Monitor.Exit, Mutex, and SpinLock, Semaphore, SemaphoreSlim) Signaling constructs. These allow a thread to pause until receiving a notification from another (event wait handles and Monitor’s Wait/Pulse methods). Framework 4.0 introduces the CountdownEvent and Barrier classes Nonblocking synchronization constructs. These protect access to a common field by calling upon processor primitives (Thread.MemoryBarrier, Thread.VolatileRead, Thread.VolatileWrite, and the Interlocked class)
28
Locking Constructs Limit the number of threads that can perform some activity or execute a section of code at a time Exclusive locking constructs are most common – allow just one thread at a time, and allow competing threads to access common data without interfering with each other. The standard exclusive locking constructs are lock (Monitor.Enter/Monitor.Exit) and Mutex The nonexclusive locking constructs are Semaphore and SemaphoreSlim
29
Thread Unsafe Example class ThreadUnsafe {
static int val1 = 1, val2 = 1; static void Go() if (val2 != 0) Console.WriteLine (val1 / val2); val2 = 0; } If Go was called by two threads simultaneously, it would be possible to get a division-by-zero error, because val2 could be set to zero in one thread right as the other thread was in between executing the if statement and Console.WriteLine
30
Using lock construct class ThreadSafe { static readonly object locker = new object(); static int val1, val2; static void Go() lock (locker) if (val2 != 0) Console.WriteLine (val1 / val2); val2 = 0; } Only one thread can lock the synchronizing object (in this case, locker) at a time, and any contending threads are blocked until the lock is released
31
Monitor.Enter and Monitor.Exit
C#’s lock statement is in fact a syntactic shortcut for a call to the methods Monitor.Enter and Monitor.Exit, with a try/finally block Monitor.Enter (locker); try { if (val2 != 0) Console.WriteLine (val1 / val2); val2 = 0; } finally Monitor.Exit (locker);
32
Deadlocks A deadlock happens when two threads each wait for a resource held by the other, so neither can proceed A threading deadlock causes participating threads to block indefinitely, unless you’ve specified a locking timeout
33
Mutex Mutex is a synchronization primitive that grants exclusive access to the shared resource to only one thread If a thread acquires a mutex, the second thread that wants to acquire that mutex is suspended until the first thread releases the mutex With a Mutex class, you call the WaitOne method to lock and ReleaseMutex to 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
34
Lock vs. Mutex A lock is specific to an application domain. Lock is a compiler keyword. It's a wrapper around the functionality of the Monitor class The Mutex is a .Net wrapper around an operating system construct, and can be used for system-wide synchronization Use Mutex whenever you want to lock a resource for the entire operating system and all applications that might try to access it Use lock when you're dealing with something that only your application will use, such as local variables, etc. (Example 2)
35
Semaphore Semaphore is a synchronization primitive that grants access to the shared resource to the number of threads specified in the constructor (capacity) A semaphore with a capacity of one is similar to a Mutex or lock Use WaitOne and Release methods to lock and unlock Semaphores can be useful in limiting concurrency – preventing too many threads from executing a particular piece of code at once
36
Semaphore Example 3 static SemaphoreSlim sem = new SemaphoreSlim(3); // Capacity of 3 static void Main() { for (int i = 1; i <= 5; i++) new Thread(Enter).Start(i); } 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();
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.