Winform: Multiple Threads Updating UI at Same Time - c#

I inherited some code that has two non-UI threads that update various WinForm controls.
The code is using InvokeRequired and Invoke to update the UI; however, I still once in a while get the error: Cross-thread operation not valid: Control 'lvReports' accessed on a thread other than it was created on.
I suspect I am dealing with a race condition and that I need to introduce a lock into the method below, but that said, I can find dozens of examples on how to update UI from a non-UI thread safely but no examples or discussion on how to deal with two threads updating the same controls in a race scenario.
So my question is: how do I rewrite the code below to handle updating the UI properly given a race condition and that I need to update UI from non-UI threads?
// two separate theads call this method in a instance of a WinForm
private void LoadReports()
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(this.LoadReports));
}
else
{
// some code removed to keep exampe simple...
SetCtlVisible(lvReports, true);
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { lvReports.Refresh(); });
}
else
{
lvReports.Refresh();
}
}
}
delegate void SetVisibleCallback(Control ctl, bool visible);
private void SetCtlVisible(Control ctl, bool visible)
{
if (ctl.InvokeRequired)
{
SetVisibleCallback d = new SetVisibleCallback(SetCtlVisible);
ctl.Invoke(d, new object[] { ctl, visible });
}
else
{
ctl.Visible = visible;
}
}
Here are some thoughts:
Does this.InvokeRequired differ from ctl.InvokeRequired at any time?
Is the second InvokeRequired test needed given the first?
Is the implementation of SetCtlVisible needed if I keep the first InvokeRequired?
Should I delete the first InvokeRequired and keep all the code in the else clause?
Is lock needed around the else clause?

Using InvokeRequired like this is an anti-pattern. You know that this method is getting called from a thread, InvokeRequired should always be true.
Now you can use it to troubleshoot your problem. If it is false then there's something seriously wrong. Throw an exception, the debugger will stop and let you find out why it isn't working properly. And always call Invoke(), invoke to a little helper method that does the rest of LoadReports().
Also note that you are using it wrong in the rest of your code. You know that the remainder of LoadReports() runs on the UI thread, you used Invoke(). No point in testing it again, including inside SetCtlVisible().
The typical reason for getting the bomb is because the thread is running LoadReports() too soon, before the form's window is created. You need to interlock that. The form's Load event is the signal.

Related

Lock hangs when called from UI to System.Threading.Thread

EDIT:
please see question history, for unchanged question in order not to invalidate comments.
I am clicking button that executes certain codes and it creates a thread (System.Threading.Thread). When I reclick button which starts process it hangs and freezes ui. What could be the reason?
public partial class ucLoader : UserControl
{
//lock object for whole instance of class ucLoader
private object lockUcLoader = new object();
//bringing info from ui
private void btnBringInfo_Click(object sender, EventArgs e)
{
lock (lockUcLoader)
{
btnBringInfo_PerformClick(false);
}
}
//using this method because it could be called when even button not visible
internal void btnBringInfo_PerformClick(bool calledFromBandInit)
{
lock (lockUcLoader) //HANGS HERE when called multiple times and ui freeze as well
//by the way I am using (repetitive) lock, because this method also called independently from btnBringInfo_Click
{
//...
this.btnLoad_PerformClick();
}
}
//Another button perform click that could be triggered elsewhere when even button not visible
private void btnLoad_PerformClick()
{
lock (lockUcLoader) //I am using (repetitive) lock, because this method also called independently from btnBringInfo_PerformClick
{
//...
Run();
}
}
//method for creating thread which System.Threading.Thread
private void Run()
{
lock (lockUcLoader) //Maybe this lock is NOT REQUIRED, as it is called by only btnLoad_PerformClick(), could you please confirm?
{
//some code that thread can be killed when available, you can ingore this two lines as they are irrelevant to subject, I think
Source = new CancellationTokenSource();
Token = Source.Token;
var shell = new WindowsShell();
Thread = new Thread((object o) =>
{
//...
var tokenInThread = (CancellationToken)o;
exitCode =TaskExtractBatchFiles(cls, shell, exitCode);
using (var logEnt = new logEntities())
{
//Do some db operation
//...
this.Invoke((MethodInvoker)delegate
{
//do some ui update operation
//...
});
}
}
Thread.Start(Token);
}
}
public void Progress(string message)
{
Invoke((MethodInvoker)delegate //ATTENTION HERE see below picture Wait occurs here
{
if (message != null && message.Trim() != string.Empty)
{
this.txtStatus.AppendText(message + Environment.NewLine);
}
});
}
}
In order to avoid get closed question, what my question is how can I prevent
below method can be accesses with out lock from background thread and ui thread
public void Progress(string message)
{
Invoke((MethodInvoker)delegate //ATTENTION HERE see below picture Wait occurs here
{
if (message != null && message.Trim() != string.Empty)
{
this.txtStatus.AppendText(message + Environment.NewLine);
}
});
}
Invoke((MethodInvoker)delegate ...
Whenever you use the lock statement in your code then you always run the risk of inducing deadlock. One of the classic threading bugs. You generally need at least two locks to get there, acquiring them in the wrong order. And yes, there are two in your program. One you declared yourself. And one you cannot see because it is buried inside the plumbing that makes Control.Invoke() work. Not being able to see a lock is what makes deadlock a difficult problem to debug.
You can reason it out, the lock inside Control.Invoke is necessary to ensure that the worker thread is blocked until the UI thread executed the delegate target. Probably also helps to reason out why the program deadlocked. You started the worker thread, it acquired the lockUcLoader lock and starts doing its job, calling Control.Invoke while doing so. Now you click the button before the worker is done, it necessarily blocks. But that makes the UI thread go catatonic and no longer capable of executing the Control.Invoke code. So the worker thread hangs on the Invoke call and it won't release the lock. And the UI thread hangs forever on the lock since the worker can't complete, deadlock city.
Control.Invoke dates from .NET 1.0, a version of the framework that has several serious design mistakes in code related to threading. While meant to be helpful, they just set death-traps for programmers to blunder into. What is unique about Control.Invoke is that it is never correct to use it.
Distinguish Control.Invoke and Control.BeginInvoke. You only ever need Invoke when you need its return value. Note how you don't, using BeginInvoke instead is good enough and instantly solves the deadlock. You'd consider Invoke to obtain a value from the UI so you can use it in the worker thread. But that induces other major threading issue, a threading race bug, the worker has no idea what state the UI is in. Say, the user might be busy interacting with it, typing a new value. You can't know what value you obtain, it will easily be the stale old value. Inevitably producing a mismatch between the UI and the work being done. The only way to avoid that mishap is to prevent the user from typing a new value, easily done with Enable = false. But now it no longer makes sense to use Invoke, you might as well pass the value when you start the thread.
So using BeginInvoke is already good enough to solve the problem. But that is not where you should stop. There is no point to those locks in the Click event handlers, all they do is make the UI unresponsive, greatly confuzzling the user. What you must do instead is set the Enable properties of those buttons to false. Set them back to true when the worker is done. Now it can't go wrong anymore, you don't need the locks and the user gets good feedback.
There is another serious problem you haven't run into yet but you must address. A UserControl has no control over its lifetime, it gets disposed when the user closes the form on which it is hosted. But that is completely out of sync with the worker thread execution, it keeps calling BeginInvoke even though the control is dead as a doornail. That will make your program bomb, hopefully on an ObjectDisposedException. A threading race bug that a lock cannot solve. The form has to help, it must actively prevent the user from closing it. Some notes about this bug in this Q+A.
For completeness I should mention the third most common threading bug that code like this is likely to suffer from. It doesn't have an official name, I call it a "firehose bug". It occurs when the worker thread calls BeginInvoke too often, giving the UI thread too much work to do. Happens easily, calling it more than about thousand times per second tends to be enough. The UI thread starts burning 100% core, trying to keep up with the invoke requests and never being able to catch up. Easy to see, it stops painting itself and responding to input, duties that are performed with a lower priority. That needs to be fixed the logical way, updating UI more than 25 times per second just produces a blur that the human eye can't observe and is therefore pointless.

c#: Invoking Methods

i am using the following function plot() to plot data on google maps.now when i am calling the same function from another button click event it is not getting executed rather going into else() statement.my plot function is as follows:
public void plot(double temp_lat, double temp_long, string temp_date, string temp_time, string temp_bty_value)
{
if (this.InvokeRequired)
{
// do something
}
else { this.Close(); }
}
i am calling this function from button click event as follows:
private void button6_Click_1(object sender, EventArgs e) /// refresh button
{
this.Invoke((MethodInvoker)(() =>
{
plot(28.5231445, 77.40388525, "17/06/20", "17:00:50", "82");
}));
}
when is the reason for this? i am new to invoking methods.please help
Edit:https://stackoverflow.com/a/43797637/6412780 The reason why i am using invocation because i was plotting 5 markers simultaneously on gmap from different threads.so for synchronization i am using invocation method.BUT now i want to update my data. i made a refresh button which contains new lat /long (passing manually here) to plot on the map.being on the same UI i called the plot() function directly ,but even then i wasn't able to execute the if statement. that is what i am doing .
In WinForms all1 UI operations – anything accessing any member of any control instance – need to be performed on the single thread executing UI operations.
Invoke can be used by a non-UI thread to cause the UI thread to execute code (with BeginInvoke this can be concurrently).
But an event handler for a control will always be running on the UI thread when triggered by the UI. So no need to switch threads. To run code on a different thread (eg. it would block the UI thread) there are various options, these days using async/await, to let the runtime work it out, is preferred.
In the question's code the event handler is already using Invoke which is pointless: it is already on the UI thread.
1 Simplifying here, the actual rules have subtleties for advanced use cases.
Invocation is required if you try to access elements, that are exclusive to one Threadfrom another Thread. It is very common when accessing GUI elements from a background thread. Here is an example:
Thread t = new Thread(() => plot(28.5231445, 77.40388525, "17/06/20", "17:00:50", "82"));
public void plot(double temp_lat, double temp_long, string temp_date, string temp_time, string temp_bty_value)
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)(() =>
{
this.Close();
}));
}
else {
this.Close();
}
}
thisseems to be a Form. If you call the Close method from another Thread you will most likely get an Exception (There are ways to prevent this, but thats not considered good style). You need to invoke that method (let the Form decide, when it is ready to execute the command)

Net tasks called using BeginInvoke on the main form not executing

I've used Visual Studio 2013 to build a C# application with a single form, and the application has two routines that update the screen. The routines that update the screen need to run on the main thread, so my own threads (which don't interact with the screen) call the BeginInvoke method on the main form when updates are required. However, something is happening somewhere in the application with the result that the two update routines stop executing. I've put logging into the app to track the calls to BeginInvoke and the execution of the update routines, and I can see that when this problem occurs, the BeginInvoke calls are made, but then nothing. When this happens, the whole application seems to freeze. I can't think of what might be causing this. How can I debug this? Is there any way of looking at what's queued to run on the main thread? When I run in debug and break into the application, all threads look normal, and the main thread doesn't appear to be doing anything, so why isn't it processing my pending update tasks?
The Control.BeginInvoke() adds the delegate to an internal thread-safe queue. And posts a message to the UI thread to tell it to go have a look in that queue. The message loop inside Application.Run() gets that message and goes about emptying the queue again, executing the delegates.
So if you don't see this happening then the most obvious reason is that the UI thread isn't inside the Application.Run() loop. A standard mistake you could make is waiting for the thread to complete for example. Very likely to cause deadlock. Never wait, if you need to run code after the thread completes then consider BackgroundWorker's RunWorkerCompleted event or TaskScheduler.FromCurrentSynchronizationContext().
The not-so-obvious failure mode of not seeing anything happening is that you are calling BeginInvoke() far too often. If you do this more than ~1000 times per second, give or take, then you'll flood that internal queue with too many delegates. The UI thread will actually be busy emptying that queue but can never catch up, always finding yet another delegate in the queue after executing one. It goes catatonic when this happens, not taking care of its normal duties anymore. Like responding to input and painting the windows. No fix for this, other than limiting the rate at which you call BeginInvoke(). Do keep the target in mind, you only have to do it as often as the user's eyes can perceive. Updating the UI at a rate more then 25 times per second is just wasted effort.
This might be due to the two update routines attempting to update the UI at the same time. I've seen strange UI behaviour, e.g. partially updated controls, when many UI updates occur in a short space of time when triggered by multiple interleaved events. The two routines are different routines, yes?
A possible way to solve this is to use asynchronous delegate invocation on the UI thread. In the code below I've assumed that your UI is a WinForms Form, and I've named the two routines UpdateA and UpdateB.
private bool isUpdating;
public delegate void UpdateDelegate();
private void UpdateA()
{
if (isUpdating)
{
this.BeginInvoke(new UpdateDelegate(UpdateA));
}
else
{
isUpdating = true;
try
{
// ... do UI updates for A
}
finally
{
isUpdating = false;
}
}
}
private void UpdateB()
{
if (isUpdating)
{
this.BeginInvoke(new UpdateDelegate(UpdateB));
}
else
{
isUpdating = true;
try
{
// ... do UI updates for B
}
finally
{
isUpdating = false;
}
}
}
By the way, I didn't use lock above to synchronise access to flag isUpdating, on the assumption that both UpdateA and UpdateB execute on the UI thread. They are invoked asynchronously by the worker threads via BeginInvoke.

C#.NET Threading Question

I am facing an issue with communication between threads in a C#.NET application.
Hope someone will guide me in the right direction about the possible solutions.
I have an application in C#.NET.It is a windows form application.
My application has two threads - One thread is the main thread (UI thread) and the other one is the child thread. Lets call the child thread the "workerThread"
There is only one form used in the application.Lets call this form the "MainForm"
The child thread is started when the MainForm loads (used the form's "Load" event handler to start the thread)
In the MainForm class, I have a variable named "stopWork" which is a public boolean variable and it serves as a flag to indicate whether the child thread should continue working or should it stop
I have another class (besides the MainForm class) which contains the method that I execute in the the child thread. Lets call this second class the "WorkerClass".
I pass a reference to the current form (the MainForm) into the constructor of the "WorkerClass"
I have a button "stop" in the main form which sets "stopWork" to "true" if its clicked and then calls "workerThread.Join()" to wait for the child thread to finish excecution.
In the child thread, the method "doWork" keeps checking the status of "parentForm.stopWork" inside a for loop. If "stopWork" is set to "true" then the loop breaks and subsequently the method ends.
Now, the issue is, once I am clicking the "stop" button ,the application hangs.
I am pasting parts of the code below so that it is easier to understand :
public partial class MainForm : Form
{
Thread workerThread = null;
ThreadStart workerThreadStart = null;
WorkerClass workerClass = null;
public bool stopWork = true;
/*.......... some code ............*/
private void MainForm_Load(object sender, EventArgs e)
{
workerThreadStart = new ThreadStart(startWork);
workerThread = new Thread(workerThreadStart);
stopWork = false;
workerThread.Start();
}
private void startWork()
{
workerClass = new WorkerClass(this);
}
private void buttonStop_Click(object sender, EventArgs e) //"stop" button
{
if (workerThread != null)
{
if (workerThread.IsAlive == true)
{
stopWork = true;
workerThread.Join();
}
}
}
/*.......... some more code ............*/
}
public class WorkerClass
{
MainForm parentForm=null;
/*......... some variables and code ........*/
public WorkerClass(MainForm parentForm)
{
this.parentForm=parentForm;
}
/* .............. some more code ...........*/
public void doWork()
{
/*.......... some variables and code ...........*/
for(int i=0;i<100000;i++)
{
// ** Here is the check to see if parentForm has set stopWork to true **
if(parentForm.stopWork==true)
break;
/*......... do some work in the loop ..........*/
}
}
/********* and more code .........*/
}
I think I may know where the problem lies.
The problem is in the "doWork" method in the child thread trying to access "stopWork" variable in the parent form when already the parent form is blocked by calling the "workerThread.Join()" method. So ,I think this is a "deadlock" problem.
Am I right in identifying the problem ? Or am I wrong and the problem lies somewhere else ?
In case this is indeed a deadlock, what are the possible solutions to solve this ?
I did a bit of googling and found lots of resources on thread synchronisation and how to avoid deadlocks. But I could not understand how to apply them specifically to my problem.
I would really appreciate any help or guidance on resolving this issue.
Yes, the code you wrote is highly vulnerable to deadlock. The BackgroundWorker class is especially prone to cause this kind of deadlock.
The problem is located in code we can't see in your snippet, the WorkerClass. You are surely doing something there that affects the UI in one way or another, always the primary reason to consider creating a thread in the first place. You probably use Control.Invoke() to have some code run on the UI thread and update a control. Perhaps also to signal that the worker thread is completed and, say, set the Enable property of a button back to true.
That's deadlock city, such code cannot run until the UI thread goes idle, back to pumping its message loop. It will never be idle in your case, it is stuck in Thread.Join(). The worker thread can't complete because the UI thread won't go idle, the UI thread can't go idle because the worker thread isn't finishing. Deadlock.
BackgroundWorker has this problem too, the RunWorkerCompleted event cannot run unless the UI thread is idle. What you need to do is not block the UI thread. Easier said than done, BGW can help you get this right because it runs an event when it completes. You can have this event do whatever you now do in the code past the Thread.Join() call. You'll need a boolean flag in your class to indicate that you are in the 'waiting for completion' state. This answer has relevant code.
Use a BackgroundWorker for this task instead. When you want to stop the task's execution, call the background worker's CancelAsync method.
Generally speaking, rolling your own threading code (on any platform) is a recipe for disaster if you don't have an expert-level understanding of multithreading (and even then it's still dangerous).

Threading Method Question

I'm using the following method to show a modeless Message Box.
public void ShowMessageBox(string Message)
{
var thread = new Thread(
() =>
{
MessageBox.Show(Message);
});
thread.Start();
}
The "() => {...}" is something I've never seen before. What is the name for this code pattern?
Also, thread.Start starts the thread, and it automatically closes once the "()=>{...}" method completes (when the Message Box is OK'ed), right? If so, can you please point me to some official documentation saying that the thread closes automatically?
Thanks!
It's the lambda operator, and read as "goes to". MSDN has a good intro: Lambda Expressions (C# Programming Guide)
One concern with your example is that you're spinning up a new thread to update the UI, the UI is intrinsically single-threaded, so background updates are generally the wrong thing to do (unless you're manually/explicitly checking InvokeRequired and calling Invoke() as needed.
Regarding the UI threading...
In WinForms every Form or Control is created on a particular thread (the "UI Thread"), and you can think of that thread as owning that control (not exactly correct, but a good way to conceptualize it). Updating the UI from that thread is safe, updating the UI from another thread runs the risk of collisions and corruption and all the usual risks of parallel/async programming.
...So... how do you safely update the UI from a background thread without blocking the UI? In short--you can't--the best you can do is block it for the bare minimum required to update the UI. This is where InvokeRequired and Invoke() come in...
Here's a sample: you should be able to drop this into the code-behind of a new form with a button and textbox.
To use:
Try commenting out either the call to SetTextAsyncSafe() or SetTextAsyncSafe() -- running both could confuse you since they won't necessarily execute in the order they're called (they're running async, remember?).
Then set a breakpoint on SetText(). You should see the "safe" call will actually call the method twice--the first call will detect InvokeRequired and will call the method a 2nd time for the correct thread by Invoke()'ing to it.
You should see an Exception thrown when SetTextAsyncUnsafe() actually gets to the textBox1.Text = value; statements. The exception will be an InvalidOperationException with a message stating "Cross-thread operation not valid" -- you can google this term for more details.
The code:
private void button1_Click(object sender, EventArgs e)
{
SetTextAsyncSafe("This update was made from the UI Thread by using Invoke()");
SetTextAsyncUnsafe("This update was made directly from the background thread and can cause problems");
}
private void SetTextAsyncUnsafe(string value)
{
new Thread(() => SetText(value, false)).Start();
}
private void SetTextAsyncSafe(string value)
{
new Thread(() => SetText(value, true)).Start();
}
private void SetText(string value, bool checkInvokeRequired)
{
if (checkInvokeRequired)
{
if (InvokeRequired)
{
Invoke(new Action(() => SetText(value, checkInvokeRequired)));
return; // early exit
}
}
textBox1.Text = value;
}
That is a Lambda. In this case, you're using it to create a new anonymous method that will be run when the new Thread is started.
It's the (near) equivalent of:
public void ShowMessageBox(string Message)
{
var thread = new Thread(ShowBox);
thread.Start(Message);
}
public void ShowBox(object message)
{
MessageBox.Show(message.ToString());
}
This is called a Lambda Expression. You can read more here.
Lambda expression, C# version 3 feature.
Don't use this code. A message box needs a parent window, something it can make sure to be on top of. It can normally find a parent by itself by iterating the windows that were created on the same thread. Not in this case though, there are no other windows, it has to pick the desktop window as the parent.
That will go wrong badly when the user is working in an app window or switches focus to another app, the message box disappears behind the foreground window. There is no obvious way for the user to tell that it is there, she'll just loses sight of it. It could be hours, if not days, before she finds it back. That thread is meanwhile consuming resources badly, you would probably never consider it if you knew that this message box requires a megabyte of memory. In extreme cases, you'll crash the program with OOM.
The common alternative in Windows UI programming is a balloon tooltip provided by a NotifyIcon. Or your own form with the TopMost property set to True so it cannot easily get lost. Also allows you to control the position, important for "non-modal" notifications that should not get in the way. Set that form's ShowWithoutActivation property to true in the form constructor so it doesn't steal the focus.
Its a statement lambda.
Yes, thread is active as long as this anonymous method is running. Since after MessageBox.Show() there is no other statements, thread will exit, and this must be true... if you are in doubt add this before start:
thread.Name = "LALALA";
And then debug your app. When the message box apear, pause execution, go to Threads View and you will see LALALA running. Click OK and pause again, there should be no "LALALA"... =)

Categories