C# ThreadPoolUse the ThreadPool type from System.Threading. Create a WaitCallback object.
ThreadPool. This C# type manages a group of threads. We process jobs in parallel using thread pools. With the ThreadPool class in .NET, we constrain threads and can incrementally update a ProgressBar.
WaitCallback. You can use WaitCallback by simply specifying the "new WaitCallback" syntax as the first argument to ThreadPool.QueueUserWorkItem. You don't need any other code to make this approach effective.
Tip WaitCallback is described as a delegate callback method to be called when the ThreadPool executes. It is a delegate that "calls back" its argument.
Parameters. You can use parameters by defining a special class and putting your important values inside of it. Then, the object is received by your method, and you can cast it. Here's an example that builds on the earlier ones.
Here We are sending 2 values to the ProcessFile threaded method. The object has contains the FileName and SelectedIndex.
Example that uses WaitCallback: C#
void Example() { // Hook up the ProcessFile method to the ThreadPool. // Note: 'a' is an argument name. Read more on arguments. ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), a); } private void ProcessFile(object a) { // I was hooked up to the ThreadPool by WaitCallback. }
ProgressBar. You can use the ProgressBar by adding the Windows Forms control in the Toolbox panel on the right to your Windows program in the designer. Next, you have to deal with progressBar1.Value, progressBar1.Minimum and progressBar1.Maximum.
Note The Value is your position between the minimum and the maximum. Initialize your ProgressBar like this.
Tip The length of the colored part of your ProgressBar is the Value's percentage of the Maximum.
Example that uses QueueUserWorkItem with argument: C#
// Special class that is an argument to the ThreadPool method. class ThreadInfo { public string FileName { get; set; } public int SelectedIndex { get; set; } } class Example { public Example() { // Declare a new argument object. ThreadInfo threadInfo = new ThreadInfo(); threadInfo.FileName = "file.txt"; threadInfo.SelectedIndex = 3; // Send the custom object to the threaded method. ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), threadInfo); } private void ProcessFile(object a) { // Constrain the number of worker threads // (Omitted here.) // We receive the threadInfo as an uncasted object. // Use the 'as' operator to cast it to ThreadInfo. ThreadInfo threadInfo = a as ThreadInfo; string fileName = threadInfo.FileName; int index = threadInfo.SelectedIndex; } }
Invoke, ProgressBar. Let's look at how to use the Invoke method on the ProgressBar instance. Unfortunately, you can't access Windows controls on worker threads, as the UI thread is separate. We have to use a delegate and Invoke onto the ProgressBar.
UpdateBar We see the delegate UpdateBar declared. This delegate syntax is different. It indicates that you need to use the method as an object.
So We set the Maximum and Minimum on the ProgressBar. We invoke the delegate method after the work is completed to increment the size.
Example that sets ProgressBar: C#
// Set progress bar length. // Here we have 6 units to complete, so that's the maximum. // Minimum usually starts at zero. progressBar1.Maximum = 6; // or any number progressBar1.Minimum = 0;
Debugger. Once you have a program working, you can take these steps to visualize the threads. First, open your threaded app in debug mode. Once your application is running in the debugger, tell it to do its job and run the threads.
So Run the debugger with the green arrow and when the threads are running, hit the pause button in the toolbar.
Example that calls Invoke: C#
public partial class MainWindow : Form { // This is the delegate that runs on the UI thread to update the bar. public delegate void BarDelegate(); // The form's constructor (autogenerated by Visual Studio) public MainWindow() { InitializeComponent(); } // When a buttom is pressed, launch a new thread private void button_Click(object sender, EventArgs e) { // Set progress bar length. progressBar1.Maximum = 6; progressBar1.Minimum = 0; // Pass these values to the thread. ThreadInfo threadInfo = new ThreadInfo(); threadInfo.FileName = "file.txt"; threadInfo.SelectedIndex = 3; ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), threadInfo); } // What runs on a background thread. private void ProcessFile(object a) { // (Omitted) // Do something important using 'a'. // Tell the UI we are done. try { // Invoke the delegate on the form. this.Invoke(new BarDelegate(UpdateBar)); } catch { // Some problem occurred but we can recover. } } // Update the graphical bar. private void UpdateBar() { progressBar1.Value++; if (progressBar1.Value == progressBar1.Maximum) { // We are finished and the progress bar is full. } } }
Next steps. Please go to Debug > Windows > Threads. This menu item will open a window that looks like the one here. You can see exactly how many threads are running in the ThreadPool.
Note The image shows ten threads total, but four of the worker threads are assigned to MainWindow.ProcessFile.
Counts. If you have a dual-core or quad-core system, you will want at most two or four demanding threads. We can do this by keeping a _threadCount field and tracking the number of running threads.
Tip With this thread count field, you will need to use a lock in the C# language to avoid having the field incorrectly read or written.
Info We see that the method was asynchronously executed. It will not start its work until there are fewer than four other worker threads.
Counts You can use SetMinThreads on ThreadPool to improve the throughput and performance in bursts of activity.
Summary. We applied the ThreadPool class to effectively manage many threads. Progress bars and fast UIs on Windows Forms applications are impressive. Threads introduce complexity.
© 2007-2021 sam allen. see site info on the changelog