I am attempting to run an async output that will last a large amount of time, and then closing the application during execution which causes the textbox to dispose. I thought this would be handled by simply returning in a try-catch statement, but VS still says there is an "unhandled" exception. Here is the code:
public void AppendOutput(string text)
{
var timeNow = DateTime.Now;
if ((DateTime.Now - previousTime).Milliseconds <= 50) return;
try
{
synchronizationContext.Post(new SendOrPostCallback(o =>
{
Output.AppendText((string)o);
}), text);
}
catch(ObjectDisposedException e)
{
return;
}
previousTime = timeNow;
}
Here is what happens in debug:
I there a reason why this is considered unhandled? I thought that's what try-catch was for. My understanding was that I could simply return because there's no need to handle exceptions for a program that is attempting to write to a textbox that has been disposed; the program should be ending the thread on its own.
What is the correct way to deal with this problem?
According to your description, you want to solve the abnormal problem that occurs during debugging.
You can add the following code in the initialization component function, as shown below:
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
Result:
Related
I am attempting to pull data from my Realtime Database in Firebase and then put that string into a TMP_Text field in unity.
There seems to be an issue with writing to a text field while within the .ContinueWith(task => portion of my code. While inside the task.isCompleted I can get the snapshot print the value after converting it to string, however, as soon as I try to write to the text field the code haults. In the example below the output is as follows.
Prints the snapshot, both key and value
Prints the value of the snapshot as a string
No errors no thing happens
The 4th print of Value does not print at all
public void PopulateScoreBoard()
{
FirebaseDatabase.DefaultInstance.GetReference("userlist").Child(LoadingScreen.userID).Child("score").GetValueAsync().ContinueWith(task =>
{
if (task.IsFaulted)
{
//handle error
scoreboard.text = "Error!";
}
else if (task.IsCompleted)
{
//get snapshot fo data
DataSnapshot snapshot = task.Result;
print(snapshot);
print(snapshot.Value.ToString());
//Get the scoreboard value within the result snapshot
scoreboard.text = snapshot.Value.ToString();
//print the same value to ensure it is working
print(snapshot.Value.ToString());
}
});
}
Looking forward to getting some input, I'm assuming there is some reason you cannot write to anything in this, however, I cannot find it. If this is the case what is my alternative?
*Update: It seems as though after further testing you cannot set anything equal to anything inside the ContinueWith(task => is that normal?
I was able to find an answer but I would still love some input to see if I am doing it right.
I changed to this code and it seems to be working fine.
public void loadData()
{
FirebaseDatabase.DefaultInstance.GetReference("userlist").ValueChanged += Script_ValueChanged;
}
private void Script_ValueChanged(object sender, ValueChangedEventArgs e)
{
scoreboard.text = e.Snapshot.Child(LoadingScreen.userID).Child("userScore").GetValue(true).ToString();
}
And then called it at start.
First, I think you could fix your initial issue by replacing ContinueWith with ContinueWithOnMainThread:
public void PopulateScoreBoard()
{
FirebaseDatabase.DefaultInstance.GetReference("userlist").Child(LoadingScreen.userID).Child("score").GetValueAsync().ContinueWithOnMainThread(task =>
{
if (task.IsFaulted)
{
//handle error
scoreboard.text = "Error!";
}
else if (task.IsCompleted)
{
//get snapshot fo data
DataSnapshot snapshot = task.Result;
print(snapshot);
print(snapshot.Value.ToString());
//Get the scoreboard value within the result snapshot
scoreboard.text = snapshot.Value.ToString();
//print the same value to ensure it is working
print(snapshot.Value.ToString());
}
});
}
The reason is that ContinueWith will return in the background. Then you perform the non-thread-safe operation scoreboard.text = "Error!";, which will cause something in the range of an exception to a crash. There's an article I wrote about this here.
Now, your answer is more correct. GetDataAsync will register a ValueChanged listener, wait for a result, and then unregister this listener. The problem is that this means that if you have stale data in your cache, your GetValueAsync will be the last value retrieved from the Firebase backend rather than the latest data.
Looking at your code, the only thing you should do different is cache the "userlist" reference and unregister later. This has to do with how Unity handles memory and object lifetime - it would be possible in your code for the text to be set on a null object:
private DatabaseReference _userListReference;
void Start() {
_userListReference = FirebaseDatabase.DefaultInstance.GetReference("userlist");
_userListReference.ValueChanged += Script_ValueChanged;
}
void OnDestroy() {
_userListReference.ValueChanged -= Script_ValueChanged;
}
private void Script_ValueChanged(object sender, ValueChangedEventArgs e)
{
scoreboard.text = e.Snapshot.Child(LoadingScreen.userID).Child("userScore").GetValue(true).ToString();
}
Due to a current bug, you MUST cache the reference to remove the event listener. If you try to retrieve it again with GetReference, you'll make a second C# copy of the underlying object and the event listener will live on.
We have built a huge winforms project, already in progress for multiple years.
Sometimes, our users get an exception which looks like this one.
The resolution of this problem seems to be:
don't acces UI components from a background thread
.
But since our project is a very big project with a lot of different threads, we don't succeed in finding all these.
Is there a way to check (with some tool or debugging option) which components are called from a background thread?
To clarify:
I created a sample winforms project with a single Form, containing two Button
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Text = "Clicked!";
}
private void button2_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
button2.BackColor = Color.Red; //this does not throw an exception
//button2.Text = "Clicked"; //this throws an exception when uncommented
});
}
}
The background color of button2 is set to red when the button is clicked. This happens in a background thread (which is considered bad behavior). However, it doesn't (immediately) throw an exception. I would like a way to detect this as 'bad behavior'. Preferably by scanning my code, but if it's only possible by debugging, (so pausing as soon as a UI component is accessed from a background thread) it's also fine.
I've got 2 recommendations to use together, the first is a Visual Studio Plugin called DebugSingleThread.
You can freeze all the threads and work on one at a time (obviously the non-main-UI threads) and see each threads access to controls. Tedious I know but not so bad with the second method.
The second method is to get the steps in order to reproduce the problem. If you know the steps to reproduce it, it will be easier to see whats causing it. To do this I made this User Action Log project on Github.
It will record every action a user makes, you can read about it here on SO: User Activity Logging, Telemetry (and Variables in Global Exception Handlers).
I'd recommend you also log the Thread ID, then when you have been able to reproduce the problem, go to the end of the log and work out the exact steps. Its not as painful as it seems and its great for getting application telemetry.
You might be able to customise this project, eg trap a DataSource_Completed event or add a dummy DataSource property that sets the real Grids DataSource property and raises an INotifyPropertyChanged event - and if its a non-main thread ID then Debugger.Break();.
My gut feeling is you're changing a control's (eg a grid) data source in a background thread (for that non-freeze feel) and thats causing a problem with synchronisation. This is what happened to the other DevExpress customer who experienced this. Its discussed here in a different thread to the one you referenced.
Is your app set to ignore cross threading intentionally?
Cross-thread operations should be blowing up all the time in winforms. It checks for them like crazy in just about every method. for a starting point check out https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs.
Somewhere in your app, somebody might have put this line of code:
Control.CheckForIllegalCrossThreadCalls = False;
Comment that out and run the app, then follow the exceptions.
(Usually you can fix the problem by wrapping the update in an invoke, e.g., in a worker thread if you see textbox1.text=SomeString; change it to `textbox.invoke(()=>{textbox1.text=SomeString;});.
You may also have to add checking for InvokeRequired, use BeginInvoke to avoid deadlocks, and return values from invoke, those are all separate topics.
this is assuming even a moderate refactor is out of the question which for even a medium sized enterprise app is almost always the case.
Note: it's not possible to guarantee successful discovery of this case thru static analysis (that is, without running the app). unless you can solve the halting problem ... https://cs.stackexchange.com/questions/63403/is-the-halting-problem-decidable-for-pure-programs-on-an-ideal-computer etc...
I did this to search for that specific situation but of course, need to adjust it to your needs, but the purpose of this is to give you at least a possibility.
I called this method SearchForThreads but since it's just an example, you can call it whatever you want.
The main idea here is perhaps adding this Method call to a base class and call it on the constructor, makes it somewhat more flexible.
Then use reflection to invoke this method on all classes deriving from this base, and throw an exception or something if it finds this situation in any class.
There's one pre req, that is the usage of Framework 4.5.
This version of the framework added the CompilerServices attribute that gives us details about the Method's caller.
The documentation for this is here
With it we can open up the source file and dig into it.
What i did was just search for the situation you specified in your question, using rudimentary text search.
But it can give you an insight about how to do this on your solution, since i know very little about your solution, i can only work with the code you put on your post.
public static void SearchForThreads(
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
var startKey = "this.Controls.Add(";
var endKey = ")";
List<string> components = new List<string>();
var designerPath = sourceFilePath.Replace(".cs", ".Designer.cs");
if (File.Exists(designerPath))
{
var designerText = File.ReadAllText(designerPath);
var initSearchPos = designerText.IndexOf(startKey) + startKey.Length;
do
{
var endSearchPos = designerText.IndexOf(endKey, initSearchPos);
var componentName = designerText.Substring(initSearchPos, (endSearchPos - initSearchPos));
componentName = componentName.Replace("this.", "");
if (!components.Contains(componentName))
components.Add(componentName);
} while ((initSearchPos = designerText.IndexOf(startKey, initSearchPos) + startKey.Length) > startKey.Length);
}
if (components.Any())
{
var classText = File.ReadAllText(sourceFilePath);
var ThreadPos = classText.IndexOf("Task.Run");
if (ThreadPos > -1)
{
do
{
var endThreadPos = classText.IndexOf("}", ThreadPos);
if (endThreadPos > -1)
{
foreach (var component in components)
{
var search = classText.IndexOf(component, ThreadPos);
if (search > -1 && search < endThreadPos)
{
Console.WriteLine($"Found a call to UI thread component at pos: {search}");
}
}
}
}
while ((ThreadPos = classText.IndexOf("Task.Run", ++ThreadPos)) < classText.Length && ThreadPos > 0);
}
}
}
I hope it helps you out.
You can get the Line number if you split the text so you can output it, but i didn't want to go through the trouble, since i don't know what would work for you.
string[] lines = classText.Replace("\r","").Split('\n');
Try that:
public static void Main(string[] args)
{
// Add the event handler for handling UI thread exceptions to the event.
Application.ThreadException += new ThreadExceptionEventHandler(exception handler);
// Set the unhandled exception mode to force all Windows Forms errors to go through the handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException += // add the handler here
// Runs the application.
Application.Run(new ......);
}
Then you can log the message and the call stack and that should give you enough information to fix the issue.
I recommend you update your GUI to handle this situation automatically for your convenience. You instead use a set of inherited controls.
The general principle here is to override the property Set methods in a way to make them Thread Safe. So, in each overridden property, instead of a straight update of the base control, there's a check to see if an invoke is required (meaning we're on a separate thread the the GUI). Then, the Invoke call updates the property on the GUI thread, instead of the secondary thread.
So, if the inherited controls are used, the form code that is trying to update GUI elements from a secondary thread can be left as is.
Here is the textbox and button ones. You would add more of them as needed and add other properties as needed. Rather than putting code on individual forms.
You don't need to go into the designer, you can instead do a find/replace on the designer files only. For example, in ALL designer.cs files, you would replace System.Windows.Forms.TextBox with ThreadSafeControls.TextBoxBackgroundThread and System.Windows.Forms.Button with ThreadSafeControls.ButtonBackgroundThread.
Other controls can be created with the same principle, based on which control types & properties are being updated from the background thread.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ThreadSafeControls
{
class TextBoxBackgroundThread : System.Windows.Forms.TextBox
{
public override string Text
{
get
{
return base.Text;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.Text = value; });
else
base.Text = value;
}
}
public override System.Drawing.Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.ForeColor = value; });
else
base.ForeColor = value;
}
}
public override System.Drawing.Color BackColor
{
get
{
return base.BackColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.BackColor = value; });
else
base.BackColor = value;
}
}
}
class ButtonBackgroundThread : System.Windows.Forms.Button
{
public override string Text
{
get
{
return base.Text;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.Text = value; });
else
base.Text = value;
}
}
public override System.Drawing.Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.ForeColor = value; });
else
base.ForeColor = value;
}
}
public override System.Drawing.Color BackColor
{
get
{
return base.BackColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.BackColor = value; });
else
base.BackColor = value;
}
}
}
}
I was playing with Task.ConfigureAwait in order to better understand what is going beyond the hood. So i got this strange behavior while combining some UI access stuff with the ConfigureAwait.
Below is the sample app using a simple windows form, with 1 Button followed by the test results:
private async void btnDoWork_Click(object sender, EventArgs e)
{
List<int> Results = await SomeLongRunningMethodAsync().ConfigureAwait(false);
int retry = 0;
while(retry < RETRY_COUNT)
{
try
{
// commented on test #1 & #3 and not in test #2
//if(retry == 0)
//throw new InvalidOperationException("Manually thrown Exception");
btnDoWork.Text = "Async Work Done";
Logger.Log("Control Text Changed", logDestination);
return;
}
catch(InvalidOperationException ex)
{
Logger.Log(ex.Message, logDestination);
}
retry++;
}
}
Now after button Click:
Test 1 Log results : (Exactly as the above code)
1. Cross-thread operation not valid: Control 'btnDoWork' accessed from a thread other than the thread it was created on.
2. Control Text Changed
Test 2 Log results : (Manual exception throw uncommented)
1. Manually thrown Exception
2. Cross-thread operation not valid: Control 'btnDoWork' accessed from a thread other than the thread it was created on.
3. Control Text Changed
Test 3 Log results : (Same as 1 but without a debugger)
1. Control Text Changed
So the questions are:
Why does the first UI Access (Cross-Thread
Operation) have the next iteration of the loop execute on the Main
Thread ?
Why doesn't the manual exception lead to the same behavior ?
Why does executing the above sample without a debugger attached (directly from exe)
doesn't show the same behavior ?
This one got me scratching my head a bit, but finally found the trick.
The code of the setter of the Button.Text property is:
set
{
if (value == null)
value = "";
if (value == this.Text)
return;
if (this.CacheTextInternal)
this.text = value;
this.WindowText = value;
this.OnTextChanged(EventArgs.Empty);
if (!this.IsMnemonicsListenerAxSourced)
return;
for (Control control = this; control != null; control = control.ParentInternal)
{
Control.ActiveXImpl activeXimpl = (Control.ActiveXImpl) control.Properties.GetObject(Control.PropActiveXImpl);
if (activeXimpl != null)
{
activeXimpl.UpdateAccelTable();
break;
}
}
}
The line throwing the exception is this.WindowText = value; (because it internally tries to access the Handle property of the button). The trick is that, right before, it sets the text property in some kind of cache:
if (this.CacheTextInternal)
this.text = value;
I'll be honest, I have no clue how this cache works, or when it is activated or not (turns out, it seems to be activated in this precise case). But because of this, the text is set even though the exception was thrown.
On further iterations of the loop, nothing happens because the property has a special check to make sure you don't set the same text twice:
if (value == this.Text)
return;
If you change your loop to set a different text every time, then you'll see that the exception is thrown consistently at each iteration.
I'm suddenly getting a strange error while debugging. Up to now the variable in the watch windows has been showing correctly. Now I am always getting this error message in the watch windows:
The function evaluation requires all threads to run
I am not able to check any variable anymore. I am not explicitly working with threads. What can I do to get it working again?
I already disabled, as mentioned in some forums, the function: "Enable property Evaluation and other implicit function Calls" in the option window of the debugger. But without success, and it gives me this error:
Error Implicit Function evaluation disabled by the user
From the msdn forum:
This isn't an error in and of itself, but more of a feature of your debugger.
Some properties require code to be executed in order for the property to be read, but if this requires cross-thread interaction, then other threads may have to run as well. The debugger doesn't do this automatically, but certainly can, with your permission.
Just click the little evaluate icon and it will run your code and evaluate the property.
For further details on this behaviour check this excelent article
I ran into this issue when just trying to get items from a table called "AGENCY" using Entity Framework:
var agencies = db.AGENCY.OrderBy(e => e.FULLNAME);
Hovering over agencies in debug mode, clicking to expand the options, and clicking Results would give the dreaded "The function evaluation requires all threads to run" with a "Do Not Enter" icon at the end that, on which, clicking did nothing.
2 possible solutions:
Add .ToList() at the end:
var agencies = db.AGENCY_TABLE.OrderBy(e => e.FULLNAME).ToList();
List<AGENCY_TABLE> agencies = db.AGENCY_TABLE.OrderBy(e => e.FULLNAME).ToList();
Credit goes to Hp93 for helping me come to this solution. In the comments on MUG4N's answer where I found this solution, it also mentions trying .Any() instead of .ToList(), but this gives a Boolean instead of a <T>, like <AGENCY> is, so it probably wouldn't help.
Workaround - try a different path in the debug options. I found that I could click on the "Non-Public Members" > "_internalQuery" > ObjectQuery > Results View and get my values that way.
MUG4N has indeed provided a correct answer however if you hover over the line of code in debug, you may be looking at something like the below. If so, click the little re-evaluate icon highlighted in the image below...
NB: I obtained this image by pinning, normally the re-evaluate icone are in the middle of the window and not down the left hand column.
You should make thread safe call because accessing Windows form controls are not Thread safe in multithreading.
This is my simple code which makes Thread safe call and sets Progress bar.
public partial class Form1 : Form
{// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void StringArgReturningVoidDelegate(string text);
private Thread demoThread = null;
public int Progresscount = 0;
static EventWaitHandle waithandler = new AutoResetEvent(false);
public Form1()
{
InitializeComponent();
}
public static bool CheckForInternetConnection()
{
try
{
using (var client = new WebClient())
{
using (var stream = client.OpenRead("http://www.google.com"))
{
return true;
}
}
}
catch
{
return false;
}
}
public void Progressincrement()
{
waithandler.WaitOne();
while (CheckForInternetConnection()==true)
{
if (Progresscount==100)
{
break;
}
SetLabel("Connected");
Progresscount += 1;
SetProgress(Progresscount.ToString());
Thread.Sleep(TimeSpan.FromSeconds(1));
}
if (Progresscount <100)
{
Startthread();
}
SetLabel("Completed");
}
public void Startthread ()
{
this.demoThread= new Thread(new ThreadStart(Progressincrement));
this.demoThread.Start();
SetLabel("Waiting for connection");
while (CheckForInternetConnection() == false) ;
waithandler.Set();
}
private void SetLabel(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.label1.InvokeRequired)
{
StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(SetLabel);
this.Invoke(d, new object[] { text });
}
else
{
this.label1.Text = text;
}
}
private void SetProgress(string Value)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.progressBar1.InvokeRequired)
{
StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(SetProgress);
this.Invoke(d, new object[] {Value});
}
else
{
this.progressBar1.Value = Convert.ToInt32(Value);
}
}
private void Form1_Load(object sender, EventArgs e)
{
Startthread();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Responsive");
}
}
For more information MSDN
This isn't an error, but more of a feature of your debugger.
The debugger doesn't do this automatically, but certainly can, with users permission. Just click the little space icon and it will run the code and evaluate the property.
I use the next workaround to pass:
var OtherThreadField = "";
Invoke(new MethodInvoker(delegate
{
OtherThreadField = ExecuteNeededMEthod();
}));
Now i have a value for OtherThreadField.
I faced the same issue and solved .The Issue arise due to username and password ,in SQL connection there is user and password but in code there no user and password. so I enable the user and the password and the issue solved
For me, this happened when trying to break on a line that accesses a complex object instance contained by a Settings Class.
A breakpoint on the following if results in Settings.Default.FindSettings with the value being "The function evaluation requires all threads to run." If I press the force eval button, it is null. Stepping with the force eval button click or not enters the if block and initializes the object. If I remove the breakpoint and add a new breakpoint following the if block, the Settings.Default.FindSettings deserializes properly with the expected values.
if (Settings.Default.FindSettings == null)
{
Settings.Default.FindSettings = new FindSettings();
}
After trial and error, I added the following code before the above if block to access the settings prior to breaking. This seems to reliably fix the problem. I do not need it in production so I wrap in conditional compiler directive. I have a comment in the code instead of a non-descript discard:
#if DEBUG
var _ = Settings.Default.FindSettings;
#endif
I am not sure if the above line would be optimized out in production since it has side effects. As I only need it while debugging, I have not checked.
I have an application where I load an image dynamically. Let's say, that image doesn't exists and we want to notify the user and then exit. In my main loop, I have exception handling which works just fine when I'm reading files with StreamReader. However, if I am throwing exception from another function, the app just crashes and in the error report I see thrown exception (IOException). To get an idea of the app:
public MainWindow()
{
try {
InitializeComponent();
Load(myFile);
} catch (IOException e) {
MessageBox.Show("Opening failure.");
Application.Current.Shutdown();
}
}
public void Load(string imgPath)
{
string tmpStr;
string[] tmp;
using (StreamReader sr = new StreamReader("myFile.txt", System.Text.Encoding.Default)) {
while ((tmpStr = sr.ReadLine()) != null) {
tmp = tmpStr.Split(' ');
...
}
}
}
private void Grid_Click(object sender, RoutedEventArgs e)
{
...
if (!File.Exists(myFile)) {
throw new IOException("File doesnt exist");
}
...
}
BUT, if I put try-catch block inside Grid_Click, it catches that exception.
The exception that is thrown in Grid-Click would not be caught by the catch statement in the MainWindow() method by design, since the method call to Grid_Click is not inside that try block.
The Grid_Click method is called when the click event is fired, which is at an asynchronous time. Only IOExceptions thrown inside the try block in MainWindow will be caught by that catch statement you have listed above.
What you call 'main loop' is just a constructor. The code does not execute under it's control.