CHAPTER 19 MULTITHREADED, PARALLEL, AND ASYNC PROGRAMMING
Printer p = new Printer();
Thread bgroundThread =
new Thread(new ThreadStart(p.PrintNumbers));
}
// This is now a background thread.
bgroundThread.IsBackground = true;
bgroundThread.Start();
Notice that this Main() method is not making a call to Console.ReadLine() to force the console to
remain visible until you press the Enter key. Thus, when you run the application, it will shut down
immediately because the Thread object has been configured as a background thread. Given that the
Main() method triggers the creation of the primary foreground thread, as soon as the logic in Main()
completes, the AppDomain unloads before the secondary thread is able to complete its work.
However, if you comment out the line that sets the IsBackground property, you will find that each
number prints to the console, as all foreground threads must finish their work before the AppDomain is
unloaded from the hosting process.
For the most part, configuring a thread to run as a background type can be helpful when the worker
thread in question is performing a noncritical task that is no longer needed when the main task of the
program is finished. For example, you could build an application that pings an e-mail server every few
minutes for new e-mails, updates current weather conditions, or some other noncritical task.
The Issue of Concurrency
When you build multithreaded applications, your program needs to ensure that any piece of shared data
is protected against the possibility of numerous threads changing its value. Given that all threads in an
AppDomain have concurrent access to the shared data of the application, imagine what might happen if
multiple threads were accessing the same point of data. As the thread scheduler will force threads to
suspend their work at random, what if thread A is kicked out of the way before it has fully completed its
work? Thread B is now reading unstable data.
To illustrate the problem of concurrency, let’s build another Console Application project named
MultiThreadedPrinting. This application will once again make use of the Printer class created
previously, but this time the PrintNumbers() method will force the current thread to pause for a
randomly generated amount of time.
public class Printer
{
public void PrintNumbers()
{
...
for (int i = 0; i < 10; i++)
{
// Put thread to sleep for a random amount of time.
Random r = new Random();
Thread.Sleep(1000 * r.Next(5));
Console.Write("{0}, ", i);
}
Console.WriteLine();
}
}
720