Title: Run threads with different priorities in C#
This example runs several different threads at different priorities. Each of the threads executes the following Counter class's Run method.
class Counter
{
// This counter's number.
public string Name;
// Initializing constructor.
public Counter(string name)
{
Name = name;
}
// Count off 10 half second intervals in the Output window.
public void Run()
{
for (int i = 1; i <= 10; i++)
{
// Display the next message.
Console.WriteLine(Name + " " + i);
// See when we should display the next message.
DateTime next_time = DateTime.Now.AddSeconds(0.5);
// Waste half a second. We don't sleep or call
// DoEvents so we don't give up control of the CPU.
while (DateTime.Now < next_time)
{
// Wait a bit.
}
}
}
}
The Counter class's constructor simply records its name so it can later display it in the Console window. The Run method loops from 1 to 10 displaying the Counter object's name and the loop count in the Console window.
The program uses the following MakeThread method to create threads.
// Make a thread with the indicated priority.
private void MakeThread(string thread_name,
ThreadPriority thread_priority)
{
// Initialize the thread.
Counter new_counter = new Counter(thread_name);
Thread thread = new Thread(new_counter.Run);
thread.Priority = thread_priority;
thread.IsBackground = true;
thread.Name = thread_name;
// Start the thread.
thread.Start();
}
This method creates a new Counter object and a Thread object to execute its Run method. It sets the thread's priority, indicates that it should run in the background, sets its name, and starts it.
The main program uses the following code to create its threads.
// Start threads with different priorities.
private void btnRunThreads_Click(object sender, EventArgs e)
{
int num_low = int.Parse(txtNumLow.Text);
for (int i = 0; i < num_low; i++)
MakeThread("Low" + i.ToString(),
ThreadPriority.BelowNormal);
int num_normal = int.Parse(txtNumNormal.Text);
for (int i = 0; i < num_normal; i++)
MakeThread("Normal" + i.ToString(),
ThreadPriority.Normal);
int num_high = int.Parse(txtNumHigh.Text);
for (int i = 0; i < num_high; i++)
MakeThread("High" + i.ToString(),
ThreadPriority.AboveNormal);
}
This code gets the number of low priority threads it should start and then calls MakeThread for each of them. It repeats those steps for the normal and high priority threads.
As the operating system sees fit, it swaps among the different Threads (and whatever else is running on the system). When you click the Run Threads button, you will probably see that the high priority threads get the most CPU time, the normal priority threads get the second most, and the low priority threads gets the least.
In the results shown on the right, the high priority threads got the most CPU and the normal priority threads got less. The low priority threads didn't get any in the period shown here.
The original example tricked me. That example ran one high priority thread, one normal priority thread, and one low priority thread. The computer I originally wrote the example for had a single processor, so they ran as expected with the high priority thread getting the most CPU time.
My current computer is a dual core system that uses hyperthreading to run two logical processors on each core for a total of four logical processors. When the program started the three threads, the operating system ran them each on a separate logical processor so they all ran at the same time. They didn't need to fight over scarce resources so they all ran at roughly the same speed.
The current version of the example lets you add more threads so they can't all run simultaneously. On my current system if I run four threads of each priority I get the expected behavior.
Aside: In Windows 10 you can get a graph showing the performance of the logical processors. To do that, follow these steps:
- Press Ctrl+Shift+Escape to open the Performance Monitor.
- Click the Performance tab.
- Right-click the graph, select Change Graph To, and pick Logical Processors.
Download the example to experiment with it and to see additional details.
|