You are on page 1of 30

NET .

22 Advanced C#
Multithreading
Presented By: John Hinz
@jhinz
Codeinbits.com
© John Hinz – All rights reserved
Agenda
• Introduction to multithreading in .NET
– Process versus thread
– Multi-threading use-cases
– Multi-threading caveats
– Working with threads
• Starting
• Argument passing
• Shutdown coordination
– Working with the thread pool
• Directly
• Asynchronous delegate invocation
• Asynchronous I/O

2
Process Anatomy

• A process is an executing instance of an application.


– Defines a virtual address space
• The contents of one process are not accessible from another process
– Libraries of code are mapped into the address space
• 1 EXE + N DLLs

3
Processes and Threads
• Threads execute code
– A path of execution through all code within a single process
– Have access to all data within that process
– Each thread has its own stack and a its own copy of CPU registers
– A process with no foreground threads exits – it can no longer
perform work
– A thread ends when the delegate passed to the Thread’s
constructor finishes executing.

4
Why Use Multi-threading?

• Opportunity to scale by parallelizing CPU-bound operations


– Assuming multi-core / multi-processor hardware
• Perform CPU-bound work while I/O operations are waiting
• Maintain a responsive UI
– Off load lengthy operations to a separate thread
– Using thread priorities to ensure user critical threads have priority

5
Multi-threading Caveats

• Slower execution time on single-core machines


• Added program complexity
– Lines of code
– Readability
– Maintainability
– Debugability
– Testability

6
Task and Data Parallelism

• There are two types of parallelism:


–Task parallelism, code that’s using the CPU is
parallelized
–Data parallelism, data collections are used
• There are variants that mix task and data
parallelism
7
Parallel Class

• Namespace System.Threading.Tasks
• Defines static methods for a parallel for and foreach
– Parallel.For
– Parallel.ForEach
• Parallel.Invoke allows you to invoke different methods
concurrently
• Parallel.Invoke is for task parallelism, Parallel.ForEach for
data parallelism
8
Parallel.For Method

• Similar to the to the ‘for loop’ statement but the iterations run in
parallel
– The order of iterations is not defined
• The Parallel.For takes 3 parameters
– First two parameters define the start and end of the loop
– The third parameter is a delegate
• https://dotnetfiddle.net/684FRO

9
Parallel.For Method (cont.)

• Stopping Parallel.For early


– A method overload of the For method accepts a third
parameter of type Action<int, ParallelLoopState>
– By defining a method with these parameters, you can
influence the outcome of the loop by invoking the Break
or Stop methods of the ParallelLoopState.
• https://dotnetfiddle.net/rSb5CP
10
Parallel.ForEach Method

• Iterates through a collection implementing


IEnumerable
• If you need to break up the loop, you can use an
overload of the ForEach method with a
ParallelLoopState parameter
• https://dotnetfiddle.net/0gIEiv

11
Parallel.Invoke

• If multiple tasks should run in parallel, you


can use the Parallel.Invoke method
• Allows the passing of an array of Action
delegates
• https://dotnetfiddle.net/EMLftN

12
Tasks

• A task represents some unit of work that should


be done.
–This unit of work can run in a separate thread
–It is also possible to start a task in a synchronized
manner
• Tasks provide much more flexibility in organizing
13
the work you need to do
Starting Tasks

• Use either the TaskFactory or the constructor of the


Task and the Start method
• When starting a task, an instance of the Task class can
be created
• The code that should run can be assigned with an
Action or Action<object> delegate
• https://dotnetfiddle.net/EpEULV
14
Futures - Results from Tasks

• When a task is finished, it can write some stateful


information to a shared object
• When defining a task to invoke the method TaskWithResult,
the generic class Task<TResult> is used
• The generic parameter defines the return type
• The method is passed to the Func delegate, and the second
parameter defines the input value
• https://dotnetfiddle.net/AO0Pcr
15
Continuation Tasks

• With tasks, you can specify that after a task is finished


another specific task should start to run
• The continuation handler has a parameter of type
Task
• A continuation task is defined by invoking the
ContinueWith method on a task.
• https://dotnetfiddle.net/UJ3Qzk
16
Cancellation Framework

• The cancellation framework enables the canceling of long-running


tasks in a standard manner. Every blocking call should support this
mechanism.
• The cancellation framework is based on cooperative behavior; it is
not forceful.
– A long-running task checks whether it is canceled and returns control
accordingly.

• https://dotnetfiddle.net/4wtiAZ
17
Thread Pools

• Thread pools are what’s behind the scenes of tasks


• The available threads are managed by the ThreadPool class
• Restrictions on thread pools:
– All thread pool threads are background threads.
– You cannot set the priority or name of a pooled thread
– Use pooled threads only for a short task.
• https://dotnetfiddle.net/8bNUOq
18
Thread Class

• If more control is needed, the Thread class can be


used.
• With the Thread class, you can create and control
threads.
• https://dotnetfiddle.net/Knh7kQ

19
Threads (cont.)

• A thread is either a background thread or a foreground


thread.
• Background threads are identical to foreground threads,
except that background threads do not prevent a process
from terminating.
• Once all foreground threads belonging to a process have
terminated, the common language runtime ends the
process.
20
Passing Data to Threads

• Two ways to pass data to a thread


– use the Thread constructor with the ParameterizedThreadStart
delegate
– create a custom class and define the method of the thread as an
instance method so that you can initialize data of the instance
before starting the thread
• https://dotnetfiddle.net/mdR0vo

21
Background Threads

• The process of the application keeps running as long as at least one


foreground thread is running.
• If more than one foreground thread is running and the Main method
ends, the process of the application remains active until all
foreground threads finish their work.
• A thread you create with the Thread class, by default, is a foreground
thread. Thread pool threads are always background threads.
• When you create a thread with the Thread class, you can define
whether it should be a foreground or background thread by setting
22 the property IsBackground.
Thread Priority

• You have had a chance to influence the scheduling by assigning a


priority to the thread
• With the Thread class, you can influence the base priority of the
thread by setting the Priority property.
– The Priority property requires a value that is defined by the ThreadPriority
enumeration. The levels defined are Highest, AboveNormal, Normal,
BelowNormal, and Lowest.

23
Controlling Threads

• A thread is created by invoking the Start method


– After invoking start a thread is still not in a running state, but is in
the Unstarted state
– A thread changes to a Running state when the thread scheduler
selects the thread to run
– Find the current state of a thread by reading the
Thread.ThreadState property

24
Controlling Threads (cont)

• To stop a thread call Thread.Abort


– When this method is called an exception of type
ThreadAbortException is thrown
• To wait for a thread to complete invoke the Thread.Join
method
– Thread.Join blocks the current operation until the joined thread is
complete

25
Blocking

• A thread is deemed blocked when its execution is paused for


some reason, such as when Sleeping or waiting for another
to end via Join.
• A blocked thread immediately yields its processor time slice,
and from then on consumes no processor time until its
blocking condition is satisfied.

26
Threading Issues

• Race Conditions
– Occur if two or more threads access the same objects
– https://dotnetfiddle.net/DlWvPo
– You can avoid the problem by locking the shared object.
– https://dotnetfiddle.net/GSc2CG
• Deadlocks
– In a deadlock, at least two threads halt and wait for each other to release a lock

27
Thread Synchronization

• Lock statement
– The lock statement provides an easy way to hold and release a lock
• Interlocked
– The Interlocked class is used to make simple statements for variables
atomic
• Monitor
– Lock is short form for Monitor. Monitor provides more control
• SpinLock
– useful if you have a large number of locks (for example, for every node
in a list) and hold times are always extremely short
28
Thread Synchronization (cont.)

• WaitHandle
– An abstract base class that you can use to wait for a signal to be set.
• Mutex (mutual exclusion)
– Offers synchronization across multiple processes
• Semaphore
– Similar to a mutex; but unlike the mutex, the semaphore can be used by multiple
threads at once
• Barrier
– For scenarios in which work is forked into multiple tasks and the work must be
joined afterward
• ReaderWriteLockSlim
– Locking mechanism to allow multiple readers, but only one writer, for a resource
29
THANK YOU.

30

You might also like