Reader small image

You're reading from  Parallel Programming and Concurrency with C# 10 and .NET 6

Product typeBook
Published inAug 2022
PublisherPackt
ISBN-139781803243672
Edition1st Edition
Right arrow
Author (1)
Alvin Ashcraft
Alvin Ashcraft
author image
Alvin Ashcraft

Alvin Ashcraft is a software engineer and developer community champion with over 25 years of experience in software development. Working primarily with Microsoft Windows, web, and cloud technologies, his career has focused primarily on the healthcare industry. He has been awarded as a Microsoft MVP 11 times, most recently as a Windows Dev MVP. Alvin works in the Philadelphia area for Allscripts, a global healthcare software company, as a principal software engineer. He is also a board member of the TechBash Foundation, where he helps organize the annual TechBash developer conference. He has previously worked for companies such as Oracle, Genzeon, CSC, and ITG Pathfinders. Originally from the Allentown, PA area, Alvin currently resides in West Grove, PA with his wife and three daughters.
Read more about Alvin Ashcraft

Right arrow

Creating and destroying threads

Creating and destroying threads are fundamental concepts of managed threading in .NET. We have already seen one code example that created a thread, but there are some additional constructors of the Thread class that should be discussed first. Also, we will look at a few methods of pausing or interrupting thread execution. Finally, we will cover some ways to destroy or terminate a thread’s execution.

Let’s get started by going into more detail regarding creating and starting threads.

Creating managed threads

Creating managed threads in .NET is accomplished by instantiating a new Thread object. The Thread class has four constructor overloads:

  • Thread(ParameterizedThreadStart): This creates a new Thread object. It does this by passing a delegate with a constructor that takes an object as its parameter that can be passed when calling Thread.Start().
  • Thread(ThreadStart): This creates a new Thread object that will execute the method to be invoked, which is provided as the ThreadStart property.
  • Thread(ParameterizedThreadStart, Int32): This adds a maxStackSize parameter. Avoid using this overload because it is best to allow .NET to manage the stack size.
  • Thread(ThreadStart, Int32): This adds a maxStackSize parameter. Avoid using this overload because it is best to allow .NET to manage the stack size.

Our first example used the Thread(ThreadStart) constructor. Let’s look at a version of that code that uses ParameterizedThreadStart to pass a value by limiting the number of iterations of the while loop:

Console.WriteLine("Hello, World!");
var bgThread = new Thread((object? data) =>
{
    if (data is null) return;
    int counter = 0;
    var result = int.TryParse(data.ToString(), 
        out int maxCount);
    if (!result) return;
    while (counter < maxCount)
    {
        bool isNetworkUp = System.Net.NetworkInformation
            .NetworkInterface.GetIsNetworkAvailable();
        Console.WriteLine($"Is network available? Answer: 
            {isNetworkUp}");
        Thread.Sleep(100);
        counter++;
    }
});
bgThread.IsBackground = true;
bgThread.Start(12);
for (int i = 0; i < 10; i++)
{
    Console.WriteLine("Main thread working...");
    Task.Delay(500);
}
Console.WriteLine("Done");
Console.ReadKey();

If you run the application, it will run just like the last example, but the background thread should only output 12 lines to the console. You can try passing different integer values into the Start method to see how that impacts the console output.

If you want to get a reference to the thread that is executing the current code, you can use the Thread.CurrentThread static property:

var currentThread = System.Threading.Thread.CurrentThread;

This can be useful if your code needs to check the current thread’s ManagedThreadId, Priority, or whether it is running in the background.

Next, let’s look at how we can pause or interrupt the execution of a thread.

Pausing thread execution

Sometimes, it is necessary to pause the execution of a thread. A common real-life example of this is a retry mechanism on a background thread. If you have a method that sends log data to a network resource, but the network is unavailable, you can call Thread.Sleep to wait for a specific interval before trying again. Thread.Sleep is a static method that will block the current thread for the number of milliseconds specified. It is not possible to call Thread.Sleep on a thread other than the current one.

We have already used Thread.Sleep in the examples in this chapter, but let’s change the code slightly to see how it can impact the order of events. Change the Thread.Sleep interval inside the thread to 10, remove the code that makes it a background thread, and change the Task.Delay() call to Thread.Sleep(100):

Console.WriteLine("Hello, World!");
var bgThread = new Thread((object? data) =>
{
    if (data is null) return;
    int counter = 0;
    var result = int.TryParse(data.ToString(), out int 
        maxCount);
    if (!result) return;
    while (counter < maxCount)
    {
        bool isNetworkUp = System.Net.NetworkInformation.
            NetworkInterface.GetIsNetworkAvailable();
        Console.WriteLine($"Is network available? Answer: 
             {isNetworkUp}");
        Thread.Sleep(10);
        counter++;
    }
});
bgThread.Start(12);
for (int i = 0; i < 12; i++)
{
    Console.WriteLine("Main thread working...");
    Thread.Sleep(100);
}
Console.WriteLine("Done");
Console.ReadKey();

When running the application again, you can see that putting a greater delay on the primary thread allows the process inside bgThread to begin executing before the primary thread completes its work:

Figure 1.2 – Using Thread.Sleep to change the order of events

Figure 1.2 – Using Thread.Sleep to change the order of events

The two Thread.Sleep intervals can be adjusted to see how they impact the console output. Give it a try!

Additionally, it is possible to pass Timeout.Infinite to Thread.Sleep. This will cause the thread to pause until it is interrupted or aborted by another thread or the managed environment. Interrupting a blocked or paused thread is accomplished by calling Thread.Interrupt. When a thread is interrupted, it will receive a ThreadInterruptedException exception.

The exception handler should allow the thread to continue working or clean up any remaining work. If the exception is unhandled, the runtime will catch the exception and stop the thread. Calling Thread.Interrupt on a running thread will have no effect until that thread has been blocked.

Now that you understand how to create an interrupt thread, let’s wrap up this section by learning how to destroy a thread.

Destroying managed threads

Generally, destroying a managed thread is considered an unsafe practice. That is why .NET 6 no longer supports the Thread.Abort method. In .NET Framework, calling Thread.Abort on a thread would raise a ThreadAbortedException exception and stop the thread from running. Aborting threads was not made available in .NET Core or any of the newer versions of .NET. If some code needs to be forcibly stopped, it is recommended that you run it in a separate process from your other code and use Process.Kill to terminate the other process.

Any other thread termination should be handled cooperatively using cancelation. We will see how to do this in the Scheduling and canceling work section. Next, let’s discuss some of the exceptions to handle when working with managed threads.

Previous PageNext Page
You have been reading a chapter from
Parallel Programming and Concurrency with C# 10 and .NET 6
Published in: Aug 2022Publisher: PacktISBN-13: 9781803243672
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Alvin Ashcraft

Alvin Ashcraft is a software engineer and developer community champion with over 25 years of experience in software development. Working primarily with Microsoft Windows, web, and cloud technologies, his career has focused primarily on the healthcare industry. He has been awarded as a Microsoft MVP 11 times, most recently as a Windows Dev MVP. Alvin works in the Philadelphia area for Allscripts, a global healthcare software company, as a principal software engineer. He is also a board member of the TechBash Foundation, where he helps organize the annual TechBash developer conference. He has previously worked for companies such as Oracle, Genzeon, CSC, and ITG Pathfinders. Originally from the Allentown, PA area, Alvin currently resides in West Grove, PA with his wife and three daughters.
Read more about Alvin Ashcraft