C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
Tip: It is useful for running many separate tasks in the background. There are better options for a single background thread.
Quote: Thread pools typically have a maximum number of threads. If all the threads are busy, additional tasks are placed in queue until they can be serviced as threads become available (Microsoft Docs).
Quote: Thread pools are often employed in server applications. Each incoming request is assigned to a thread from the thread pool, so the request can be processed asynchronously, without tying up the primary thread or delaying the processing of subsequent requests (Microsoft Docs).
The program does batch processing. Consider ThreadPool. This better automates multiple short-lived threads.
It makes three or more threads. Also consider ThreadPool, which handles multiple threads, not just one.
It uses Windows Forms. Consider BackgroundWorker, an easy-to-use control that you can add in the Visual Studio designer.
BackgroundWorkerYou need one extra thread. Use BackgroundWorker. Also consider just using a Thread object and the ThreadStart method.
ThreadStartYou have many short-lived threads. Use ThreadPool—the alternative is to implement your own ThreadPool with Thread objects. This is harder.
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.
}
Here: We are sending 2 values to the ProcessFile threaded method. The object has contains the FileName and SelectedIndex.
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;
}
}
Note: The Value is your position between the minimum and the maximum. Initialize your ProgressBar like this.
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;
UpdateBar: We see the delegate UpdateBar declared. This delegate syntax is different. It indicates that you need to use the method as an object.
DelegatesSo: 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 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.
}
}
}
So: Run the debugger with the green arrow and when the threads are running, hit the pause button in the toolbar.
Note: The image shows ten threads total, but four of the worker threads are assigned to MainWindow.ProcessFile.
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.
LockInfo: 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.
ThreadPool.SetMinThreadsExample that counts threads: C#
// Lock on this object.
readonly object _countLock = new object();
private void ProcessFile(object argument)
{
// Constrain the number of worker threads
while (true)
{
// Prevent other threads from changing this under us
lock (_countLock)
{
if (_threadCount < 4)
{
// Start the processing
_threadCount++;
break;
}
}
Thread.Sleep(50);
}
// Do work...
}