Multithreading With C Cookbook 2nd Edition Eugene Agafonov PDF Download
Multithreading With C Cookbook 2nd Edition Eugene Agafonov PDF Download
https://ebookgate.com/product/multithreading-with-c-cookbook-2nd-
edition-eugene-agafonov/
https://ebookgate.com/product/case-files-family-medicine-2nd-edition-
eugene-c-toy/
ebookgate.com
https://ebookgate.com/product/c-concurrency-in-action-practical-
multithreading-meap-1st-edition-anthony-williams/
ebookgate.com
https://ebookgate.com/product/machine-learning-with-r-cookbook-2nd-
edition-ashishsingh-bhatia/
ebookgate.com
https://ebookgate.com/product/case-files-obstetrics-and-gynecology-
lange-case-files-2nd-edition-eugene-c-toy/
ebookgate.com
Case Files Internal Medicine 4th Edition Eugene C. Toy
https://ebookgate.com/product/case-files-internal-medicine-4th-
edition-eugene-c-toy/
ebookgate.com
https://ebookgate.com/product/web-development-with-django-cookbook-
bendoraitis/
ebookgate.com
https://ebookgate.com/product/case-files-neuroscience-case-files-1st-
edition-eugene-c-toy/
ebookgate.com
https://ebookgate.com/product/c-cookbook-2e-ed-edition-stephens/
ebookgate.com
https://ebookgate.com/product/programming-with-ansi-c-2nd-ed-edition-
trivedi/
ebookgate.com
Multithreading with
C# Cookbook
Second Edition
Eugene Agafonov
BIRMINGHAM - MUMBAI
Multithreading with C# Cookbook
Second Edition
All rights reserved. No part of this book may be reproduced, stored in a retrieval system,
or transmitted in any form or by any means, without the prior written permission of the
publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the
information presented. However, the information contained in this book is sold without
warranty, either express or implied. Neither the author, nor Packt Publishing, and its
dealers and distributors will be held liable for any damages caused or alleged to be
caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the
companies and products mentioned in this book by the appropriate use of capitals.
However, Packt Publishing cannot guarantee the accuracy of this information.
ISBN 978-1-78588-125-1
www.packtpub.com
Credits
Eugene Agafonov leads the development department at ABBYY and lives in Moscow.
He has over 15 years of professional experience in software development, and he started
working with C# when it was in beta version. He is a Microsoft MVP in ASP.NET since 2006,
and he often speaks at local software development conferences, such as DevCon Russia,
about cutting-edge technologies in modern web and server-side application development. His
main professional interests are cloud-based software architecture, scalability, and reliability.
Eugene is a huge fan of football and plays the guitar with a local rock band. You can reach him
at his personal blog, eugeneagafonov.com, or find him on Twitter at @eugene_agafonov.
ABBYY is a global leader in the development of document recognition, content capture, and
language-based technologies and solutions that are integrated across the entire information
life cycle.
I'd like to dedicate this book to my dearly beloved wife, Helen, and son,
Nikita.
About the Reviewers
Philip Pierce is a software developer with 20 years of experience in mobile, web, desktop,
and server development, database design and management, and game development. His
background includes creating A.I. for games and business software, converting AAA games
between various platforms, developing multithreaded applications, and creating patented
client/server communication technologies.
Philip has won several hackathons, including Best Mobile App at the AT&T Developer
Summit 2013, and a runner up for Best Windows 8 App at PayPal's Battlethon Miami.
His most recent project was converting Rail Rush and Temple Run 2 from the Android
platform to Arcade platforms.
f http://www.rocketgamesmobile.com
f http://www.philippiercedeveloper.com
www.PacktPub.com
At www.PacktPub.com, you can also read a collection of free technical articles, sign up
for a range of free newsletters and receive exclusive discounts and offers on Packt books
and eBooks.
TM
https://www2.packtpub.com/books/subscription/packtlib
Do you need instant solutions to your IT questions? PacktLib is Packt's online digital book
library. Here, you can search, access, and read Packt's entire library of books.
Why Subscribe?
f Fully searchable across every book published by Packt
f Copy and paste, print, and bookmark content
f On demand and accessible via a web browser
Table of Contents
Preface v
Chapter 1: Threading Basics 1
Introduction 2
Creating a thread in C# 2
Pausing a thread 6
Making a thread wait 7
Aborting a thread 8
Determining a thread state 10
Thread priority 12
Foreground and background threads 14
Passing parameters to a thread 16
Locking with a C# lock keyword 19
Locking with a Monitor construct 22
Handling exceptions 24
Chapter 2: Thread Synchronization 27
Introduction 27
Performing basic atomic operations 28
Using the Mutex construct 31
Using the SemaphoreSlim construct 32
Using the AutoResetEvent construct 34
Using the ManualResetEventSlim construct 36
Using the CountDownEvent construct 38
Using the Barrier construct 39
Using the ReaderWriterLockSlim construct 41
Using the SpinWait construct 44
i
Table of Contents
ii
Table of Contents
iii
Preface
Not so long ago, a typical personal computer CPU had only one computing core, and the
power consumption was enough to cook fried eggs on it. In 2005, Intel introduced its first
multiple-core CPU, and since then, computers started developing in a different direction.
Low-power consumption and a number of computing cores became more important than
a row computing core performance. This lead to programming paradigm changes as well.
Now, we need to learn how to use all CPU cores effectively to achieve the best performance,
and at the same time, we need to save battery power by running only the programs that we
need at a particular time. Besides that, we need to program server applications in a way to
use multiple CPU cores or even multiple computers as efficiently as possible to support as
many users as we can.
To be able to create such applications, you have to learn to use multiple CPU cores in your
programs effectively. If you use the Microsoft .NET development platform and C#, this book
will be a perfect starting point for you to program fast and responsive applications.
The purpose of this book is to provide you with a step-by-step guide for multithreading and
parallel programming in C#. We will start with the basic concepts, going through more and
more advanced topics based on the information from previous chapters, and we will end with
real-world parallel programming patterns, Universal Windows applications, and cross-platform
applications samples.
Chapter 2, Thread Synchronization, describes thread interaction details. You will learn why we
need to coordinate threads together and the different ways of organizing thread coordination.
Chapter 3, Using a Thread Pool, explains the thread pool concept. It shows how to use a
thread pool, how to work with asynchronous operations, and the good and bad practices
of using a thread pool.
v
Preface
Chapter 4, Using the Task Parallel Library, is a deep dive into the Task Parallel Library (TPL)
framework. This chapter outlines every important aspect of TPL, including task combination,
exception management, and operation cancelation.
Chapter 6, Using Concurrent Collections, describes the standard data structures for parallel
algorithms included in .NET Framework. It goes through sample programming scenarios for
each data structure.
Chapter 7, Using PLINQ, is a deep dive into the Parallel LINQ infrastructure. The chapter
describes task and data parallelism, parallelizing a LINQ query, tweaking parallelism options,
partitioning a query, and aggregating the parallel query result.
Chapter 8, Reactive Extensions, explains how and when to use the Reactive Extensions
framework. You will learn how to compose events and how to perform a LINQ query against
an event sequence.
Chapter 9, Using Asynchronous I/O, covers in detail the asynchronous I/O process, including
files, networks, and database scenarios.
Chapter 10, Parallel Programming Patterns, outlines the solutions to common parallel
programming problems.
Chapter 11, There's More, covers the aspects of programming asynchronous applications for
Windows 10, OS X, and Linux. You will learn how to work with Windows 10 asynchronous APIs
and how to perform the background work in Universal Windows applications. Also, you will get
familiar with cross-platform .NET development tools and components.
vi
Preface
Conventions
In this book, you will find a number of styles of text that distinguish between different kinds of
information. Here are some examples of these styles, and an explanation of their meaning.
Code words in text are shown as follows: "When the program is run, it creates a thread that
will execute a code in the PrintNumbersWithDelay method."
New terms and important words are shown in bold. Words that you see on the screen, in
menus or dialog boxes for example, appear in the text like this: "Right-click on the References
folder in the project, and select the Manage NuGet Packages… menu option".
vii
Preface
Reader feedback
Feedback from our readers is always welcome. Let us know what you think about this book—
what you liked or may have disliked. Reader feedback is important for us to develop titles that
you really get the most out of.
If there is a topic that you have expertise in and you are interested in either writing or
contributing to a book, see our author guide on www.packtpub.com/authors.
Customer support
Now that you are the proud owner of a Packt book, we have a number of things to help you to
get the most from your purchase.
1. Log in or register to our website using your e-mail address and password.
2. Hover the mouse pointer on the SUPPORT tab at the top.
3. Click on Code Downloads & Errata.
4. Enter the name of the book in the Search box.
5. Select the book for which you're looking to download the code files.
6. Choose from the drop-down menu where you purchased this book from.
7. Click on Code Download.
Once the file is downloaded, please make sure that you unzip or extract the folder using the
latest version of:
viii
Preface
Errata
Although we have taken every care to ensure the accuracy of our content, mistakes do
happen. If you find a mistake in one of our books—maybe a mistake in the text or the code—
we would be grateful if you would report this to us. By doing so, you can save other readers
from frustration and help us improve subsequent versions of this book. If you find any errata,
please report them by visiting http://www.packtpub.com/submit-errata, selecting
your book, clicking on the errata submission form link, and entering the details of your
errata. Once your errata are verified, your submission will be accepted and the errata will
be uploaded on our website, or added to any list of existing errata, under the Errata section
of that title. Any existing errata can be viewed by selecting your title from http://www.
packtpub.com/support.
Piracy
Piracy of copyright material on the Internet is an ongoing problem across all media. At Packt,
we take the protection of our copyright and licenses very seriously. If you come across any
illegal copies of our works, in any form, on the Internet, please provide us with the location
address or website name immediately so that we can pursue a remedy.
We appreciate your help in protecting our authors, and our ability to bring you valuable content.
Questions
You can contact us at [email protected] if you are having a problem with any
aspect of the book, and we will do our best to address it.
ix
Threading Basics
1
In this chapter, we will cover the basic tasks to work with threads in C#. You will learn the
following recipes:
f Creating a thread in C#
f Pausing a thread
f Making a thread wait
f Aborting a thread
f Determining a thread state
f Thread priority
f Foreground and background threads
f Passing parameters to a thread
f Locking with a C# lock keyword
f Locking with a Monitor construct
f Handling exceptions
1
Threading Basics
Introduction
At some point of time in the past, the common computer had only one computing unit and
could not execute several computing tasks simultaneously. However, operating systems could
already work with multiple programs simultaneously, implementing the concept of multitasking.
To prevent the possibility of one program taking control of the CPU forever, causing other
applications and the operating system itself to hang, the operating systems had to split a
physical computing unit across a few virtualized processors in some way and give a certain
amount of computing power to each executing program. Moreover, an operating system must
always have priority access to the CPU and should be able to prioritize CPU access to different
programs. A thread is an implementation of this concept. It could be considered as a virtual
processor that is given to the one specific program and runs it independently.
Therefore, while it was possible to enhance computer processors, making them execute more
and more commands per second, working with threads was usually an operating system task.
There was no sense in trying to compute some tasks in parallel on a single-core CPU because
it would take more time than running those computations sequentially. However, when
processors started to have more computing cores, older programs could not take advantage
of this because they just used one processor core.
The recipes in this chapter focus on performing some very basic operations with threads
in the C# language. We will cover a thread's life cycle, which includes creating, suspending,
making a thread wait, and aborting a thread, and then, we will go through the basic
synchronization techniques.
Creating a thread in C#
Throughout the following recipes, we will use Visual Studio 2015 as the main tool to write
multithreaded programs in C#. This recipe will show you how to create a new C# program and
use threads in it.
2
Chapter 1
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other
prerequisites. The source code for this recipe can be found in the BookSamples\Chapter1\
Recipe1 directory.
How to do it...
To understand how to create a new C# program and use threads in it, perform the
following steps:
3
Threading Basics
2. Make sure that the project uses .NET Framework 4.6 or higher; however, the code in
this chapter will work with previous versions.
4
Chapter 1
6. Run the program. The output will be something like the following screenshot:
How it works...
In step 1 and 2, we created a simple console application in C# using .Net Framework version
4.0. Then, in step 3, we included the System.Threading namespace, which contains all the
types needed for the program. Then, we used the using static feature from C# 6.0, which
allows us to use the System.Console type's static methods without specifying the type name.
In step 4, we defined the PrintNumbers method, which will be used in both the main and
newly created threads. Then, in step 5, we created a thread that runs PrintNumbers. When
we construct a thread, an instance of the ThreadStart or ParameterizedThreadStart
delegate is passed to the constructor. The C# compiler creates this object behind the scenes
when we just type the name of the method we want to run in a different thread. Then, we start
a thread and run PrintNumbers in the usual manner on the main thread.
5
Threading Basics
As a result, there will be two ranges of numbers from 1 to 10 randomly crossing each other.
This illustrates that the PrintNumbers method runs simultaneously on the main thread and
on the other thread.
Pausing a thread
This recipe will show you how to make a thread wait for some time without wasting operating
system resources.
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other
prerequisites. The source code for this recipe can be found at BookSamples\Chapter1\
Recipe2.
How to do it...
To understand how to make a thread wait without wasting operating system resources,
perform the following steps:
6
Chapter 1
WriteLine(i);
}
}
How it works...
When the program is run, it creates a thread that will execute a code in the
PrintNumbersWithDelay method. Immediately after that, it runs the PrintNumbers
method. The key feature here is adding the Thread.Sleep method call to a
PrintNumbersWithDelay method. It causes the thread executing this code to wait a
specified amount of time (2 seconds in our case) before printing each number. While a thread
sleeps, it uses as little CPU time as possible. As a result, we will see that the code in the
PrintNumbers method, which usually runs later, will be executed before the code in the
PrintNumbersWithDelay method in a separate thread.
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other prerequisites.
The source code for this recipe can be found at BookSamples\Chapter1\Recipe3.
How to do it...
To understand how a program waits for some computation in another thread to complete in
order to use its result later, perform the following steps:
7
Threading Basics
using static System.Console;
using static System.Threading.Thread;
How it works...
When the program is run, it runs a long-running thread that prints out numbers and waits
two seconds before printing each number. But, in the main program, we called the t.Join
method, which allows us to wait for the thread t to complete working. When it is complete, the
main program continues to run. With the help of this technique, it is possible to synchronize
execution steps between two threads. The first one waits until another one is complete and
then continues to work. While the first thread waits, it is in a blocked state (as it is in the
previous recipe when you call Thread.Sleep).
Aborting a thread
In this recipe, we will describe how to abort another thread's execution.
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other prerequisites.
The source code for this recipe can be found at BookSamples\Chapter1\Recipe4.
8
Chapter 1
How to do it...
To understand how to abort another thread's execution, perform the following steps:
3. Using the static System.Threading.Thread, add the following code snippet below
the Main method:
static void PrintNumbersWithDelay()
{
WriteLine("Starting...");
for (int i = 1; i < 10; i++)
{
Sleep(TimeSpan.FromSeconds(2));
WriteLine(i);
}
}
9
Threading Basics
How it works...
When the main program and a separate number-printing thread run, we wait for six seconds
and then call a t.Abort method on a thread. This injects a ThreadAbortException
method into a thread, causing it to terminate. It is very dangerous, generally because this
exception can happen at any point and may totally destroy the application. In addition, it is
not always possible to terminate a thread with this technique. The target thread may refuse to
abort by handling this exception by calling the Thread.ResetAbort method. Thus, it is not
recommended that you use the Abort method to close a thread. There are different methods
that are preferred, such as providing a CancellationToken object to cancel a thread
execution. This approach will be described in Chapter 3, Using a Thread Pool.
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other prerequisites.
The source code for this recipe can be found at BookSamples\Chapter1\Recipe5.
How to do it...
To understand how to determine a thread state and acquire useful information about it,
perform the following steps:
10
Chapter 1
{
WriteLine("Starting...");
WriteLine(CurrentThread.ThreadState.ToString());
for (int i = 1; i < 10; i++)
{
Sleep(TimeSpan.FromSeconds(2));
WriteLine(i);
}
}
How it works...
When the main program starts, it defines two different threads; one of them will be
aborted and the other runs successfully. The thread state is located in the ThreadState
property of a Thread object, which is a C# enumeration. At first, the thread has a
ThreadState.Unstarted state. Then, we run it and assume that for the duration of
30 iterations of a cycle, the thread will change its state from ThreadState.Running to
ThreadState.WaitSleepJoin.
11
Threading Basics
If this does not happen, just increase the number of iterations. Then, we abort the first
thread and see that now it has a ThreadState.Aborted state. It is also possible that the
program will print out the ThreadState.AbortRequested state. This illustrates, very well,
the complexity of synchronizing two threads. Keep in mind that you should not use thread
abortion in your programs. I've covered it here only to show the corresponding thread state.
Finally, we can see that our second thread t2 was completed successfully and now has a
ThreadState.Stopped state. There are several other states, but they are partly deprecated
and not as useful as those we examined.
Thread priority
This recipe will describe the different options for thread priority. Setting a thread priority
determines how much CPU time a thread will be given.
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other prerequisites.
The source code for this recipe can be found at BookSamples\Chapter1\Recipe6.
How to do it...
To understand the workings of thread priority, perform the following steps:
threadOne.Priority = ThreadPriority.Highest;
12
Chapter 1
threadTwo.Priority = ThreadPriority.Lowest;
threadOne.Start();
threadTwo.Start();
Sleep(TimeSpan.FromSeconds(2));
sample.Stop();
}
class ThreadSample
{
private bool _isStopped = false;
while (!_isStopped)
{
counter++;
}
13
Threading Basics
How it works...
When the main program starts, it defines two different threads. The first one, threadOne,
has the highest thread priority ThreadPriority.Highest, while the second one, that
is threadTwo, has the lowest ThreadPriority.Lowest priority. We print out the main
thread priority value and then start these two threads on all available cores. If we have more
than one computing core, we should get an initial result within two seconds. The highest
priority thread should calculate more iterations usually, but both values should be close.
However, if there are any other programs running that load all the CPU cores, the situation
could be quite different.
Note that this is an illustration of how an operating system works with thread prioritization.
Usually, you should not write programs relying on this behavior.
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other prerequisites.
The source code for this recipe can be found at BookSamples\Chapter1\Recipe7.
How to do it...
To understand the effect of foreground and background threads on a program, perform the
following steps:
14
Chapter 1
threadOne.Start();
threadTwo.Start();
How it works...
When the main program starts, it defines two different threads. By default, a thread that we
create explicitly is a foreground thread. To create a background thread, we manually set the
IsBackground property of the threadTwo object to true. We configure these threads in a
way that the first one will be completed faster, and then we run the program.
15
Threading Basics
After the first thread is complete, the program shuts down and the background thread is
terminated. This is the main difference between the two: a process waits for all the foreground
threads to complete before finishing the work, but if it has background threads, they just
shut down.
It is also important to mention that if a program defines a foreground thread that does not get
completed; the main program does not end properly.
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other prerequisites.
The source code for this recipe can be found at BookSamples\Chapter1\Recipe8.
How to do it...
To understand how to pass parameters to a thread, perform the following steps:
16
Chapter 1
}
class ThreadSample
{
private readonly int _iterations;
WriteLine("--------------------------");
WriteLine("--------------------------");
17
Threading Basics
threadThree.Start();
threadThree.Join();
WriteLine("--------------------------");
int i = 10;
var threadFour = new Thread(() => PrintNumber(i));
i = 20;
var threadFive = new Thread(() => PrintNumber(i));
threadFour.Start();
threadFive.Start();
How it works...
When the main program starts, it first creates an object of the ThreadSample
class, providing it with a number of iterations. Then, we start a thread with the object's
CountNumbers method. This method runs in another thread, but it uses the number 10,
which is the value that we passed to the object's constructor. Therefore, we just passed
this number of iterations to another thread in the same indirect way.
There's more…
Another way to pass data is to use the Thread.Start method by accepting an object that
can be passed to another thread. To work this way, a method that we started in another
thread must accept one single parameter of the type object. This option is illustrated by
creating a threadTwo thread. We pass 8 as an object to the Count method, where it is
cast to an integer type.
The next option involves the use of lambda expressions. A lambda expression defines a
method that does not belong to any class. We create such a method that invokes another
method with the arguments needed and start it in another thread. When we start the
threadThree thread, it prints out 12 numbers, which are exactly the numbers we passed
to it via the lambda expression.
The use of lambda expressions involves another C# construct named closure. When we
use any local variable in a lambda expression, C# generates a class and makes this variable
a property of this class. So, actually, we do the same thing as in the threadOne thread, but
we do not define the class ourselves; the C# compiler does this automatically.
This could lead to several problems; for example, if we use the same variable from several
lambdas, they will actually share this variable value. This is illustrated by the previous
example where, when we start threadFour and threadFive, they both print 20 because
the variable was changed to hold the value 20 before both threads were started.
18
Chapter 1
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other prerequisites.
The source code for this recipe can be found at BookSamples\Chapter1\Recipe9.
How to do it...
To understand how to use the C# lock keyword, perform the following steps:
19
Threading Basics
{
Count--;
}
}
20
Chapter 1
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join();
WriteLine("Correct counter");
How it works...
When the main program starts, it first creates an object of the Counter class. This class
defines a simple counter that can be incremented and decremented. Then, we start three
threads that share the same counter instance and perform an increment and decrement in
a cycle. This leads to nondeterministic results. If we run the program several times, it will
print out several different counter values. It could be 0, but mostly won't be.
This happens because the Counter class is not thread-safe. When several threads access
the counter at the same time, the first thread gets the counter value 10 and increments it to
11. Then, a second thread gets the value 11 and increments it to 12. The first thread gets the
counter value 12, but before a decrement takes place, a second thread gets the counter value
12 as well. Then, the first thread decrements 12 to 11 and saves it into the counter, and the
second thread simultaneously does the same. As a result, we have two increments and only
one decrement, which is obviously not right. This kind of a situation is called a race condition
and is a very common cause of errors in a multithreaded environment.
21
Threading Basics
To make sure that this does not happen, we must ensure that while one thread works with the
counter, all other threads wait until the first one finishes the work. We can use the lock keyword
to achieve this kind of behavior. If we lock an object, all the other threads that require an access
to this object will wait in a blocked state until it is unlocked. This could be a serious performance
issue and later, in Chapter 2, Thread Synchronization, you will learn more about this.
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other prerequisites.
The source code for this recipe can be found at BookSamples\Chapter1\Recipe10.
How to do it...
To understand the multithreaded error deadlock, perform the following steps:
22
Chapter 1
object lock2 = new object();
lock (lock2)
{
Thread.Sleep(1000);
WriteLine("Monitor.TryEnter allows not to get stuck, returning
false after a specified timeout is elapsed");
if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5)))
{
WriteLine("Acquired a protected resource succesfully");
}
else
{
WriteLine("Timeout acquiring a resource!");
}
}
WriteLine("----------------------------------");
lock (lock2)
{
WriteLine("This will be a deadlock!");
Sleep(1000);
lock (lock1)
{
WriteLine("Acquired a protected resource succesfully");
}
}
How it works...
Let's start with the LockTooMuch method. In this method, we just lock the first object, wait
for a second, and then lock the second object. Then, we start this method in another thread
and try to lock the second object and then the first object from the main thread.
If we use the lock keyword like in the second part of this demo, there will be a deadlock.
The first thread holds a lock on the lock1 object and waits while the lock2 object gets
free; the main thread holds a lock on the lock2 object and waits for the lock1 object to
become free, which will never happen in this situation.
23
Threading Basics
Actually, the lock keyword is syntactic sugar for the Monitor class usage. If we were to
disassemble code with lock, we would see that it turns into the following code snippet:
bool acquiredLock = false;
try
{
Monitor.Enter(lockObject, ref acquiredLock);
}
finally
{
if (acquiredLock)
{
Monitor.Exit(lockObject);
}
}
Therefore, we can use the Monitor class directly; it has the TryEnter method, which
accepts a timeout parameter and returns false if this timeout parameter expires before
we can acquire the resource protected by lock.
Handling exceptions
This recipe will describe how to handle exceptions in other threads properly. It is very
important to always place a try/catch block inside the thread because it is not possible
to catch an exception outside a thread's code.
Getting ready
To work through this recipe, you will need Visual Studio 2015. There are no other prerequisites.
The source code for this recipe can be found at BookSamples\Chapter1\Recipe11.
How to do it...
To understand the handling of exceptions in other threads, perform the following steps:
24
Chapter 1
using static System.Console;
using static System.Threading.Thread;
try
{
t = new Thread(BadFaultyThread);
t.Start();
}
catch (Exception ex)
{
WriteLine("We won't get here!");
}
25
Threading Basics
How it works...
When the main program starts, it defines two threads that will throw an exception. One of
these threads handles an exception, while the other does not. You can see that the second
exception is not caught by a try/catch block around the code that starts the thread. So, if
you work with threads directly, the general rule is to not throw an exception from a thread, but
to use a try/catch block inside a thread code instead.
In the older versions of .NET Framework (1.0 and 1.1), this behavior was different and
uncaught exceptions did not force an application shutdown. It is possible to use this policy
by adding an application configuration file (such as app.config) that contains the following
code snippet:
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="1" />
</runtime>
</configuration>
26
Thread Synchronization
2
In this chapter, we will describe some of the common techniques of working with shared
resources from multiple threads. You will learn the following recipes:
Introduction
As we saw in Chapter 1, Threading Basics, it is problematic to use a shared object
simultaneously from several threads. However, it is very important to synchronize those threads
so that they perform operations on that shared object in a proper sequence. In the Locking with
a C# lock keyword recipe, we faced a problem called the race condition. The problem occurred
because the execution of those multiple threads was not synchronized properly. When one
thread performs increment and decrement operations, the other threads must wait for their
turn. Organizing threads in such a way is often referred to as thread synchronization.
There are several ways to achieve thread synchronization. First, if there is no shared object,
there is no need for synchronization at all. Surprisingly, it is very often the case that we can
get rid of complex synchronization constructs by just redesigning our program and removing
a shared state. If possible, just avoid using a single object from several threads.
27
Thread Synchronization
If we must have a shared state, the second approach is to use only atomic operations. This
means that an operation takes a single quantum of time and completes at once, so no other
thread can perform another operation until the first operation is complete. Therefore, there is
no need to make other threads wait for this operation to complete and there is no need to use
locks; this in turn, excludes the deadlock situation.
If this is not possible and the program's logic is more complicated, then we have to use
different constructs to coordinate threads. One group of these constructs puts a waiting
thread into a blocked state. In a blocked state, a thread uses as little CPU time as possible.
However, this means that it will include at least one so-called context switch—the thread
scheduler of an operating system will save the waiting thread's state and switch to another
thread, restoring its state by turn. This takes a considerable amount of resources; however,
if the thread is going to be suspended for a long time, it is good. These kind of constructs
are also called kernel-mode constructs because only the kernel of an operating system is
able to stop a thread from using CPU time.
In case, we have to wait for a short period of time, it is better to simply wait than switch
the thread to a blocked state. This will save us the context switch at the cost of some
wasted CPU time while the thread is waiting. Such constructs are referred to as user-mode
constructs. They are very lightweight and fast, but they waste a lot of CPU time in case a
thread has to wait for long.
To use the best of both worlds, there are hybrid constructs; these try to use user-mode
waiting first, and then, if a thread waits long enough, it switches to the blocked state,
saving CPU resources.
In this chapter, we will look through the aspects of thread synchronization. We will cover how
to perform atomic operations and how to use the existing synchronization constructs included
in .NET Framework.
Getting ready
To step through this recipe, you will need Visual Studio 2015. There are no other prerequisites.
The source code for this recipe can be found at BookSamples\Chapter2\Recipe1.
How to do it...
To understand basic atomic operations, perform the following steps:
On the following day he set out to call on some old parishioners, and
had not gone very far on his way when he encountered Tom
Musgrave riding along.
"If ever I met such a fellow as you are, Howard! We all thought
you'd been eaten by cannibals!"
"Sorry to disappoint you!—but there are no cannibals in Spain!"
"Well, crocodiles!—it's all one!—and here's Osborne gone off to
Paris, clean out of his wits over Miss Watson!"
"How came you to make such a mistake with regard to Miss
Watson?"
"Faith! I don't know that there was any mistake! Her people are wild
with her for not having Osborne—but there seems to be some other
fellow in the background—someone she had met at her aunt's—and
she seems fully determined to have her own way. She has,
absolutely, left them at Croydon, and gone to stay with her younger
brother, where there will be nobody to look after her from morning
to night!"
This story unfortunately received confirmation during the morning;
and on the following day, when he rode over to the Rectory to see
Purvis, it received a still more disquieting aspect. Emma had been
seen in the company of a Captain Conway at A——, a man who was
said to be highly connected, though of this there was no certain
proof—but who, on the other hand, was well known to be a
profligate. Heavy at heart he returned to the Castle.
As he sat with Lady Osborne over the fire that night, she told him
more of her history than ever he had previously known.
He had always deplored the inferiority of her son and daughter to
their mother, but hitherto it had never occurred to him that she had
been conscious of it herself.
"I have known but little happiness in my life," she said. "My father,
Lord Foulke, was a gambler; and, in view of the increasing difficulty
of living, my mother believed it to be her duty to marry off all her
daughters as soon as they came out. I was the third of five girls, and
married when scarcely sixteen—no more than a child. I could not
endure Lord Osborne—my every instinct revolted against him—but
though I implored my father and mother, with tears, to spare me,
they would not listen to me. No one may know the misery of my
married life. When I was about twenty-three, however, my husband
died, leaving me with two young children—the boy so backward that
I believed him for a time to be deficient; but as I spared no effort to
develop him he gradually improved. Not long afterwards my father
died from an accident. The shock brought a stroke on my mother,
depriving her of the power of speech, which she never afterwards
recovered, though she lingered on for several years. My brother,
despite the remonstrances of the doctor, insisted on her removal to
the Dower House, and short as was the drive, she never recovered
from it; so that I dared not attempt to bring her here. As it was
seldom possible to leave her, I could see but little of my children, for
as the Dower House was small, and indifferently built, she could not
endure their noise. But never had I loved her so well. Qualities, that
I had never before discerned in her, now showed themselves, and
we were drawn together as we never had been before. At her death
I returned home, to find my daughter almost a stranger to me. Julia
was now fourteen, and her pretty manners, which I had believed to
be the expression of her affection for me, had merely served as a
mask to her serious defects of character. Perhaps unjustly, I
dismissed her governess, believing her to be blamed, and
endeavoured myself to correct them, but I had come too late, and it
only served to estrange her the further. Osborne, on the other hand,
has always held for me the simple affection of his childhood, and his
faults are rather of a negative than of a positive character, but he
cares for little beyond hunting and fishing—we have almost nothing
in common. Until you came, Arthur, I had scarcely known what it
was to have a companion."
There was a slight falter in her voice as she uttered the last words,
and she looked at her visitor wistfully.
His eyes, half veiled by their lashes, were fixed on the glowing
embers, and he remained silent. Once again Emma's soft hand
trembled in his own, and he was conscious of the beating of her
heart. Why had he not taken her into his arms, then and there, to
shelter in his breast for ever?
"Arthur, you are not listening to me!"
There was a note of reproach in the gentle voice at his side.
"I assure you, Lady Osborne, that I am deeply concerned and
distressed to hear of all that you have suffered. Perhaps in view of
my office it is scarcely orthodox for me to say how very unfair it has
all seemed—but from the point of view of a simple human being, it
is impossible to think otherwise."
Nothing could have been kinder than the tone in which he
pronounced these words; but that she had expected something
altogether different was quite evident by the expression of
disappointment which overspread her countenance, as she shrank
into the shadow.
After a moment's silence he continued:
"The want of sympathy between parents and children is only too
common, but there must have been a total absence of all natural
feeling on the part of your brother, with regard to Lady Foulke, when
he could act in such a manner towards her. The counterpart of it,
however, I witnessed at the bedside of my cousin. His son, as you
know, broke his neck in the hunting field, as his father lay dying. I
was deputed to tell him, and did so in fear and trembling as to the
possible effect it might have on him, but he just looked round at me
and said: 'And a good thing, too!' Although I had been aware that
the relations between them were very unfortunate, I had not
believed it possible that there could be such an estrangement
between father and son."
After a pause Mr. Howard then announced that he had written to his
agent to expect him on the following Saturday.
"Oh, surely not!" exclaimed his hostess, leaning forward in
expostulation. "Cumberland will be quite intolerable in this weather—
I have heard that the cold there is beyond everything!"
"I have yet to learn that I am in a galloping consumption. I assure
you there is no country more delightful and wonderful than
Cumberland in the grasp of winter!"
"I am well aware a Northman will swear anything with respect to his
country!"
"Madam! I protest!"
"Oh, protest away! you are all of you alike! I had hoped that you
might have been prevailed upon to remain with us until Easter—in
which case Osborne would have come back at once."
"Do not you think he had much better remain where he is? In the
gay world of Paris he will have everything to distract him, and may
possibly find someone to replace Miss Watson?"
"I do not think so."
"Surely you do not believe that Osborne will remain inconsolable for
ever?"
There was a gleam of humour in his dark eyes as he turned them
towards her. In all his intimate knowledge of his former pupil, it had
certainly never occurred to him that he possessed a heart of untold
depths!
"No. What I believe is, that he will revert to his former indifference
towards women, and never marry at all."
"That would be very much to be deplored."
"I am not so sure of that. He is scarcely fitted to attract a superior
mind, and you could not expect me to welcome an inferior one, or to
view, without pain, an unwilling bride forced into his arms."
A day or two later Lady Osborne stood beneath the portico, to wish
her guest "God-speed."
"Remember I shall be counting on you for an invitation!" she said,
smiling.
He bowed low.
"I shall have to secure a fair chatelaine, madam, in order to receive
you worthily!"
How little did he realize that his idle words were as a naked sword in
her breast.
CHAPTER XVII
Sam was walking along the High Street of Guildford just as the
coach drove up to the stage; and, for the moment, thinking less of
anything in the world than of Emma, when, to his amazement, she
suddenly appeared on the platform. Hastening forward, he lifted her
down; but seeing she could scarcely maintain her composure,
forbore to question her, and, drawing her hand within his arm, he
led her home.
He now lived entirely with Mr. Curtis at his residence, in a quiet
suburban road, not far off: a large, red-brick house, standing in its
own grounds, and furnished with all the comfort and suitability of
wealth and refinement. As soon as they were seated by a
comfortable fire in the library, Emma, in a few words, informed her
brother of all that had happened. He was much moved by the
recital, but deeply gratified that she had come to him at once—
indeed his satisfaction at having her would have been without
bounds, had it not been for his indignation at the conduct of Robert
and Jane, and the shock he had sustained at finding Emma travelling
by herself.
Presently Mr. Curtis, who had been out, returned to the house, and
entered the room. Sam at once introduced his sister, and while
sparing her feelings as much as possible, made him acquainted with
a sufficient account of what had occurred, to let him see that it was
impossible for Emma to return to Croydon. He then announced his
intention of at once seeking for suitable lodgings for his sister and
himself, but Mr. Curtis steadily refused to countenance such an
arrangement, insisting that as he already regarded Sam as a son, he
had some justification in venturing to hope that Miss Emma might
come to look on him as her father, and in the meantime his house
was as truly at her service. Emma thanked him charmingly, but
begged for permission to look for a situation, as governess, or
companion. On perceiving, however, the mortification she was
occasioning, both to Sam and Mr. Curtis, she was soon obliged to
give way.
Before very long her box was forwarded from Croydon, and both
Robert and Jane wrote more suitably than might have been
expected, expressing considerable regret that she had left them.
Emma was now more at ease than she had been since her quiet
time with Elizabeth, although she daily missed little Augusta; but her
health had been injured by all she had gone through. Her cheek,
once rounded with perfect health, was now thin and worn, and to
Sam's dismay she did not appear to be regaining her vitality as the
weeks went by. In view of her half-confession to him, he feared she
was suffering from a secret sorrow, and he and Mr. Curtis spared no
effort to restore her.
Towards the end of February Elizabeth's marriage was arranged, and
Mrs. John Purvis, with whom she had been residing, and from whose
house the wedding was to take place, kindly invited the whole
family, including Augusta. Emma's embarrassment at meeting Robert
and Jane was considerably lessened by this arrangement, and she
and the child were inseparable during the few days they spent
together. Penelope and Margaret had obtained leave to be present,
and both appeared improved by having been provided with
occupation, other than hunting for husbands. Mary Edwards had also
been invited, and Emma was now able to satisfy herself that she was
not wholly indifferent to Sam.
Elizabeth looked very sweet and handsome in her white bonnet and
shawl, and the bridegroom distinguished himself not a little by
forgetting neither cheque nor ring.
The sisters had been truly happy to have met together again, and
their parting was much less sorrowful than before, both bride and
Welcome to Our Bookstore - The Ultimate Destination for Book Lovers
Are you passionate about books and eager to explore new worlds of
knowledge? At our website, we offer a vast collection of books that
cater to every interest and age group. From classic literature to
specialized publications, self-help books, and children’s stories, we
have it all! Each book is a gateway to new adventures, helping you
expand your knowledge and nourish your soul
Experience Convenient and Enjoyable Book Shopping Our website is more
than just an online bookstore—it’s a bridge connecting readers to the
timeless values of culture and wisdom. With a sleek and user-friendly
interface and a smart search system, you can find your favorite books
quickly and easily. Enjoy special promotions, fast home delivery, and
a seamless shopping experience that saves you time and enhances your
love for reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!
ebookgate.com