Main thread locking up in C# - c#

I am faced with a problem. I am clicking a button that is calling several methods, although the main thread is locking up, so I created an instance of my class (which is Form1) e.g. Form1Object and then the button called the methods as so: Form1Object.Check1 and so on.
Although the thread still locked up (i.e. the GUI became unresponsive for a period) Is there anyway of getting around this, any examples would be greatly appreciated.
The code in question is below:
private void StartChecks_Click(object sender, EventArgs e)
{
Form1 Form1Object = new Form1();
Form1Object.InitChecks();
}
public void InitChecks()
{
Check1();
Check2();
Check3();
Check4();
Check5();
Check6();
Check7();
}

Creating a new Form does not start a new Thread.
You will have to move those CheckN() methods to a BackgroundWorker.
private void StartChecks_Click(object sender, EventArgs e)
{
Form1 Form1Object = new Form1();
var worker = new BackgroundWorker();
worker.DoWork += (s, arg) =>
{
Form1Object.InitChecks();
};
// add progress, completed events
worker.RunWorkerAsync();
}
But note that this require that the checks are independent and do not interact with any Control.

What you need to do is start a parallel thread to do the check, so you won't lock up the main thread:
private void StartChecks_Click(object sender, EventArgs e)
{
Form1 Form1Object = new Form1();
Thread t = new Thread(
o =>
{
Form1Object.InitChecks();
});
t.Start();
}
Hopefully you don't need to actually retrieve anything from those calculations, so you can just fire and forget about it.

You have several options here, and use them depending of your skill/preference/requirement:
if you don't update anything on the form while you process, start another thread and call everything on that thread, and update UI when appropriate (when everything is finished)
if you need to update things on your form while processing, you have several options:
either use Application.DoEvents() from the processing loop of every method you use
start a new thread then update form controls with Invoke() - if you try to update them directly, you'll be in trouble
If you care to comment and decide for one of the options, I can provide more info on just that...

Related

C# Threading still make UI unresponsive

Well , I have a form1 which has buttons and if you click one of its button
It would load the UserControl into panel in form1
That usercontrol1 contains a lot of data like Database,charts and picture boxes too. So it would definitely make the User Interface unresponsive while loading.
So I read some article and I found out that I need to run it through another thread so I tried it and it just increase the performance by a little bit.
The usercontrol1 still make the GUI unresponsive for about 3-5 sec and what if my data become larger.
I want to make it responsive and show to user that still loading by running the animated picturebox and stop if its finish loading
here is my code:
private void click_dashb_Click(object sender, EventArgs e)
{
ParameterizedThreadStart pts = new ParameterizedThreadStart(load_UserControl);
Thread t = new Thread(pts);
t.Start();
//Animated Picturebox to show user that UI is loading
pictureBox1.Enabled = true;
hover.Location = new Point(42, 130);
}
private void load_UserControl(object state)
{
Invoke(new Action(() =>
{
//load user control through another thread
while (panel1.Controls.Count > 0)
panel1.Controls[0].Dispose();
Home frm = new Home();
frm.AutoScroll = true;
panel1.Controls.Add(frm);
frm.Show();
}));
//Stop the animated GIF means the load is finish!
pictureBox1.Enabled = false;
}
If you help me about this problem. I might apply it to all of my works. because most of it contains large data.
Thanks stackoverflow community :)
EDIT:
After reading the comments suggesting to use Background worker . I tried to use it. but still getting a little bit unresponsiveness
Here's the new code:
private void click_dashb_Click(object sender, EventArgs e)
{
bgw.RunWorkerAsync();
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
try
{
BeginInvoke((MethodInvoker)delegate
{
while (panel1.Controls.Count > 0)
panel1.Controls[0].Dispose();
Home frm = new Home();
frm.AutoScroll = true;
panel1.Controls.Add(frm);
frm.Show();
});
}
catch (Exception x)
{
MessageBox.Show("An error occured while performing operation" + x);
}
}
private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("Operation Cancelled");
}
else
{
MessageBox.Show("Operation Completed");
}
}
It's a little bit better but i still got a little unresponsiveness. Can you check out my code and what's wrong with this.?
thanks again
The problem with your code is that although you run the load_UserControl code in a new thread, that code calls Invoke which effectively makes al the code run on the UI thread again. I can image you did that because accessing Forms and PictureBoxes requires running on the UI thread.
The solution (in general) is to do non-UI work on a seperate thread and then switch back to the UI thread to update the visual controls.
To do this, you can conveniently use the BackgroundWorker class. In the DoWork event handler you do the heavy computation, in the RunWorkerCompleted event handler you update the controls. If you want, you can even update some controls (like a progressbar) during the work by means of the ProgressChanged event handler.
Well, just starting a new thread doesn't make the UI responsive by definition. You need to make the thread so that it actually does stuff in parallel.
Your thread does not, as it basically executes all code in this.Invoke.
That being said: Your code needs to be executed in this.Invoke, as almost everything you do needs to be done on the UI thread.
So in your case, there's really no point in parallelizing stuff, as there's no way to do what you want to do without blocking the UI thread and no technique I know of (Threads, Tasks, BackgroundWorker, etc.) will solve this problem.

Form is not available and doesn't update while a loop is in progress

I have a method that has a for loop in it. In the for loop I want to update some label's text on the mainform, but the changes are only done after the loop ends.
I tried to do it on another thread like this:
Thread firstthread = new Thread(new ThreadStart(myMethod));
firstthread.Start();
When I did that I got an InvalidOperationException because of trying to access controls on another thread or something like that.
How should I update the labels(or other controls) on the mainform from a loop while the loop is in progress?
You should use a BackgroundWorker. Place your long running loop inside of the DoWork event handler; it will run in a background thread and not block the UI thread. You can set ReportProgress to true and then attach an event handler to that to allow you to update a label (or whatever else) periodically. The ProgressReported event runs in the UI thread. You can also add a handler to the Completed event which runs in the UI thread as well.
You can look at the MSDN page for BackgroundWorker for details and code samples.
You should check the Invoke and BeginInvoke methods on the Form (for Windows.Forms) or on the Dispatcher object of the window (for WPF).
For example:
this.BeginInvoke(new Action(() => this.Text = "ciao"));
changes the title bar of the form.
BeginInvoke is asynchronous - it doesn't wait for the change to happen - while Invoke is synchronous and blocks until the change is done. Unless you have specifically that need, I would suggest using BeginInvoke which reduces the chances of an accidental deadlock.
This will allow you to update UI from a concurrent thread - and works whatever threading mechanism you are using (TPL tasks, plain Thread, etc.).
As Servy said, you can use something like in this simple example:
public partial class Form1 : Form
{
BackgroundWorker bgw;
public Form1()
{
InitializeComponent();
bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);
bgw.WorkerReportsProgress = true;
}
void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
string text = (string)e.UserState;
SetValue(text);//or do whatever you want with the received data
}
void SetValue(string text)
{
this.label1.Text = text;
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 10000; i++)
{
string text = "Value is " + i.ToString();
bgw.ReportProgress(1, text);
Thread.Sleep(1000);
}
}
private void button1_Click(object sender, EventArgs e)
{
bgw.RunWorkerAsync();
}
}

How can a new Form be run on a different thread in C#?

I'm just trying to run a new thread each time a button click even occurs which should create a new form. I tried this in the button click event in the MainForm:
private void button1_Click(object sender, EventArgs e)
{
worker1 = new Thread(new ThreadStart(thread1));
worker2 = new Thread(new ThreadStart(thread2));
worker1.Start();
worker2.Start();
}
private void thread1()
{
SubForm s = new SubForm();
s.Show();
}
private void thread2()
{
SubForm s = new SubForm();
s.Show();
}
The code in the Subform button click event goes like this:
private void button1_Click(object sender, EventArgs e)
{
int max;
try
{
max = Convert.ToInt32(textBox1.Text);
}
catch
{
MessageBox.Show("Enter numbers", "ERROR");
return;
}
progressBar1.Maximum = max;
for ( long i = 0; i < max; i++)
{
progressBar1.Value = Convert.ToInt32(i);
}
}
Is this the right way? Because I'm trying to open two independent forms, operations in one thread should not affect the other thread.
Or is BackGroundworker the solution to implement this? If yes, can anyone please help me with that?
You do not need to run forms in separate threads. You can just call s.Show() on multiple forms normally. They will not block each other.
Of course, if you’re doing something else, like some sort of calculation or other task that takes a long while, then you should run that in a separate thread, but not the form.
Here is a bit of code that will let you create a progress bar that shows progress for a long process. Notice that every time to access the form from inside the thread, you have to use .Invoke(), which actually schedules that invocation to run on the GUI thread when it’s ready.
public void StartLongProcess()
{
// Create and show the form with the progress bar
var progressForm = new Subform();
progressForm.Show();
bool interrupt = false;
// Run the calculation in a separate thread
var thread = new Thread(() =>
{
// Do some calculation, presumably in some sort of loop...
while ( ... )
{
// Every time you want to update the progress bar:
progressForm.Invoke(new Action(
() => { progressForm.ProgressBar.Value = ...; }));
// If you’re ready to cancel the calculation:
if (interrupt)
break;
}
// The calculation is finished — close the progress form
progressForm.Invoke(new Action(() => { progressForm.Close(); }));
});
thread.Start();
// Allow the user to cancel the calculation with a Cancel button
progressForm.CancelButton.Click += (s, e) => { interrupt = true; };
}
Although I'm not 100% aware of anything that says running completely seperate forms doing completely isolated operations in their own threads is dangerous in any way, running all UI operations on a single thread is generally regarded as good practice.
You can support this simply by having your Subform class use BackgroundWorker. When the form is shown, kick off the BackgroundWorker so that it processes whatever you need it to.
Then you can simply create new instances of your Subform on your GUI thread and show them. The form will show and start its operation on another thread.
This way the UI will be running on the GUI thread, but the operations the forms are running will be running on ThreadPool threads.
Update
Here's an example of what your background worker handlers might look like - note that (as usual) this is just off the top of my head, but I think you can get your head around the basic principles.
Add a BackgroundWorker to your form named worker. Hook it up to the following event handlers:
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Executed on GUI thread.
if (e.Error != null)
{
// Background thread errored - report it in a messagebox.
MessageBox.Show(e.Error.ToString());
return;
}
// Worker succeeded.
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Executed on GUI thread.
progressBar1.Value = e.ProgressPercentage;
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
// Executed on ThreadPool thread.
int max = (int)e.Argument;
for (long i = 0; i < max; i++)
{
worker.ReportProgress(Convert.ToInt32(i));
}
}
Your click handler would look something like:
void button1_Click(object sender, EventArgs e)
{
int max;
try
{
// This is what you have in your click handler,
// Int32.TryParse is a much better alternative.
max = Convert.ToInt32(textBox1.Text);
}
catch
{
MessageBox.Show("Enter numbers", "ERROR");
return;
}
progressBar1.Maximum = max;
worker.RunWorkerAsync(max);
}
I hope that helps.
Try this. It runs the new Form on its own thread with its own message queues and what not.
Run this code:
new Thread(new ThreadStart(delegate
{
Application.Run(new Form());
})).Start();
Use Thread.CurrentThread.GetHashCode() to test that is runs on different thread.
It's possible to run different forms on different threads. There are two caveats I'm aware of:
Neither form may be an MDI client of the other. Attempting to make a form an MDI client of another when the forms have different threads will fail.
If an object will be sending events to multiple forms and all forms use the same thread, it's possible to synchronize the events to the main thread before raising it. Otherwise, the event must be raised asynchronously and each form must perform its own synchronization mechanism for incoming events.
Obviously it's desirable not to have any window's UI thread get blocked, but using separate threads for separate windows may be a nice alternative.

C# regularly return values from a different thread

I'm very new to multithreading and lack experience. I need to compute some data in a different thread so the UI doesn't hang up, and then send the data as it is processed to a table on the main form. So, basically, the user can work with the data that is already computed, while other data is still being processed. What is the best way to achieve this? I would also be very grateful for any examples. Thanks in advance.
If you don't want to use the Background worker as answered by KMan you can create a thread yourself.
private void startJob(object work) {
Thread t = new Thread(
new System.Threading.ParameterizedThreadStart(methodToCall)
);
t.IsBackground = true; // if you set this, it will exit if all main threads exit.
t.Start(work); // this launches the methodToCall in its own thread.
}
private void methodToCall(object work) {
// do the stuff you want to do
updateGUI(result);
}
private void updateGUI(object result) {
if (InvokeRequired) {
// C# doesn't like cross thread GUI operations, so queue it to the GUI thread
Invoke(new Action<object>(updateGUI), result);
return;
}
// now we are "back" in the GUI operational thread.
// update any controls you like.
}
Checkout this BackgroundWorker sample document.
Initialise your background worker object
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
// I need to compute some data in a different thread so the UI doesn't hang up
// Well! ompute some data here.
bw.ReportProgress(percentOfCompletion, yourData) // and then send the data as it is processed
// percentOfCompletion-int, yourData-object(ie, you can send anything. it will be boxed)
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// to a table on the main form. So, basically, the user can work with the data that is already computed, while other data is still being processed
List<string> yourData = e.UserState as List<string>; // just for eg i've used a List.
}
What is the best way to achieve this?
RunWorkerAsync(); //This will trigger the DoWork() method
Use registry key to share the data between the threads
You can send the data to static variable, static variables are shared across threads.

Splash Screen that doesn't go away

I'm using a Splash Screen from Here. I love how simple it is. But the problem with it is that the splash screen doesn't go away until I click on it. When run within the IDE it works fine. Any ideas? I'd attach the code here but its not inserting properly for some reason.
private System.Windows.Forms.Timer timer1;
//private Splash sp=null;
public Form1()
{
InitializeComponent();
Thread th = new Thread(new ThreadStart(DoSplash));
//th.ApartmentState = ApartmentState.STA;
//th.IsBackground=true;
th.Start();
Thread.Sleep(3000);
th.Abort();
Thread.Sleep(1000);
}
private void DoSplash()
{
Splash sp = new Splash();
sp.ShowDialog();
}
private void timer1_Tick(object sender, System.EventArgs e)
{
// sp.Close();
}
First of all, the way the splash screen on that page is done, using Thread.Abort, is not the right way to do things.
Never call Thread.Abort, unless you're in the process of shutting down the AppDomain the thread lives in.
Let me reiterate that for emphasis. The only time you should call Thread.Abort is when you know enough about Thread.Abort and how it behaves to know that you should never call it.
Take a look at this other question on StackOverflow: Multi-Threaded splash screen in c#?.
If you want to keep your existing solution, a possible better way would be to drop a timer into the splash screen form, set its timer to the time you want the splash screen to stay on screen, and call Close in its Tick event handler.
In the same venue, I would simply fire off that original thread, and remove the other lines.
In other words, from the first code block on that page, I would keep these two lines:
Thread th = new Thread(new ThreadStart(DoSplash));
th.Start();
Couple that with that timer on the form that makes the form self-closing, and you're in way better shape than trying to get to grips with Thread.Abort.
Which you should not call.
The DoSplash should probably call sp.Show() instead of sp.ShowDialog()
But calling Sleep(x000) form your main thread to show a splash screen isn't very efficient, and Thread.Abort() should be reserved for better use too.
A better approach is to close your SplashForm with a Timer and set a minimum delay. On startup you can Show() and Update() the SplahForm and continue to load stuff. The timer event won't fire until the MainForm is finished initializing and enters the EventLoop. No threads needed, and the MainForm doesn't have to be involved either.
Just to give you the main ingredients of a MessageLoop driven SplashForm:
public partial class SplashForm : Form
{
// default stuff
public static void Splash()
{
var s = new SplashForm();
s.Show();
s.Update();// force paint
}
private void SplashForm_Load(object sender, EventArgs e)
{
Timer t = new Timer();
t.Interval = 1; // wait for EventLoop
t.Tick += GoAway;
t.Enabled = true;
}
private void GoAway(object sender, EventArgs e)
{
this.Close();
}
}
and then, in Program.cs,
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SplashForm.Splash();
Application.Run(new MainForm());
That's an ugly implementation. You should check out this SO thread. That describes how to use the VisualBasic.NET namespace from C# and the OnCreateSplashScreen method to do a much cleaner splash screen implementation.

Categories