Reputation: 23
Essentially I've been using multithreading and it hasn't been working the way it should be. I immediately tried to describe the issue in a title to find an answer online but found nothing in relation.
Here's an application I developed to better understand multitasking so I can effectively use in actual applications.
So essentially what it does is you write something in the textbox and choose how many threads you want and it will append the log box on the bottom. So it will show how many times each thread has run BUT the issue is that it still makes the UI freeze whilst in the background.
Here's the output it gives on 3 threads (it can handle a low amount of (less than 10) threads):
Here is the complete code -
public partial class thread : Form
{
Thread[] threads;
int amountOf;
bool stop = false;
int threadAmt = 0;
public thread()
{
InitializeComponent();
}
delegate void SetTextCallback(string text);
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
amountOf = (int)amtThreads.Value;
threads = new Thread[amountOf];
//Define threads
for (int i = 0; i < amountOf; i++)
{
threads[i] = new Thread(new ThreadStart(job));
}
//Start threads
foreach (Thread t in threads)
{
t.IsBackground = true;
t.Start();
}
}
private void logIt(string text)
{
if (outputResult.InvokeRequired)
{
SetTextCallback cb = new SetTextCallback(logIt);
Invoke(cb, new object[] { text });
}
else
outputResult.AppendText(text);
}
private void job()
{
int threadNum = threadAmt++;
int howMany = 0;
do
{
howMany++;
logIt("Thread: " + threadNum + " : Processed " + howMany + " times : Saying " + writeText.Text + Environment.NewLine);
Thread.Sleep(1);
}
while (!stop);
}
private void Start_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
Start.Enabled = false;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
MessageBox.Show("Error: " + e.Error.Message);
else if (e.Cancelled)
MessageBox.Show("Application canceled.");
}
private void Stop_Click(object sender, EventArgs e)
{
stop = true;
backgroundWorker1.CancelAsync();
Stop.Enabled = false;
}
private void Clear_Click(object sender, EventArgs e)
{
outputResult.Clear();
}
}
The UI continues to freeze after putting 10 or more threads. Another thing I wanted to know is pausing and resuming the threads. When you stop the threads loop then re-enable it it'll only show a single result. It wont continue the loop.
Upvotes: 2
Views: 1153
Reputation:
Your problem is not so much creating excessive threads rather your threads are excessively updating the UI.
Your job
method has a very tight loop where you call logIt
then sleep for one millisecond then repeat the process. The log marshals the call to the UI thread where outputResult.AppendText(text);
is called. This marshalling happens over the message pump.
You're essentially overflowing the message pump with essentially updates to the TextBox
and so the UI becomes unresponsive being unable to process anything else.
Multiply that out by 10 threads all logging with miniscule waits between logging and your UI will freeze.
Consider increasing the Thread.Sleep
to say Thread.Sleep(500)
for 1/2 second.
Change this code:
private void job()
{
int threadNum = threadAmt++;
int howMany = 0;
do
{
howMany++;
logIt("Thread: " + threadNum + " : Processed " + howMany + " times : Saying " + writeText.Text + Environment.NewLine);
Thread.Sleep(1); // Oww!! Should this have been 1000 instead of 1. 1000 is 1 second.
}
while (!stop);
}
...to:
private void job()
{
int threadNum = threadAmt++;
int howMany = 0;
do
{
howMany++;
logIt("Thread: " + threadNum + " : Processed " + howMany + " times : Saying " + writeText.Text + Environment.NewLine);
Thread.Sleep(500); // e.g. 1/2 second
}
while (!stop);
}
It's great you are interested in threading. .NET has made threading much easier since Thread
was introduced, particularly when threads need to manipulate the UI. Now days it is usually better not to explicitly create threads but to use the alternative APIs.
You might want to look .NET asynchronous methods via the async
and the await
keywords as they might be quite useful in your case.
A topic for another time
Upvotes: 2