Scenario
I have a C# windows forms application that has a number of processes. These processes run on separate threads and all communicate back to the Main Form class with updates to a log window and a progress bar. I'm using the following code below, which up until now has worked fine, however, I have a few questions.
Code
delegate void SetTextCallback(string mxID, string text);
public void UpdateLog(string mxID, string text)
{
if (txtOutput.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(UpdateLog);
this.BeginInvoke(d, new object[] { mxID, text });
}
else
{
UpdateProgressBar(text);
}
}
Question
Will, calling the above code about 10 times a second, repeatedly, give me errors, exceptions or generally issues?.....Or more to the point, should it give me any of these problems?
Occasionally I get OutofMemory Exceptions开发者_C百科 and the program always seems to crash around this bit of code......
Yes, it is technically possible for this code to cause OOM. That will happen when the UI thread cannot keep up with the worker thread. Each Control.BeginInvoke() adds a delegate to an internal List<Delegate>
maintained by Windows Forms. The message pump empties that list. If it cannot keep up with the rate at which the worker thread calls BeginInvoke then the list grows without bounds and, eventually, causes OOM.
If this is really called only 10 times per second and it code only updates a progress bar and the UI thread is otherwise idle then OOM should never happen. That it does happen suggests that you somehow call this method a lot more frequently than 10 times per second. Or the real code does a lot more than just update a PB, the "UpdateLog" name suggests it does. Using Invoke instead of BeginInvoke solves that problem, but will slow down the worker.
This code is OK, the reason of exceptions is somewhere else in the program. You may optimize this by calling UpdateProgressBar directly or through BeginInvoke, instead of calling UpdateLog.
delegate void SetTextCallback(string text); public void UpdateLog(string mxID, string text) { if (txtOutput.InvokeRequired) { SetTextCallback d = new SetTextCallback(UpdateProgressBar); this.BeginInvoke(d, new object[] { text }); } else { UpdateProgressBar(text); } }
But I beleive that there is something else that is not shown in this post.
BeginInvoke returns an IAsyncResult which is ignored in your code. Just use Invoke instead.
精彩评论