tags:

views:

468

answers:

3

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 and the program always seems to crash around this bit of code......

+1  A: 

BeginInvoke returns an IAsyncResult which is ignored in your code. Just use Invoke instead.

Henrik
Control.BeginInvoke is similar to the Win32 API PostMessage function. delegate.BeginInvoke starts another thread
Asher
delegate.BeginInvoke Does not starts another thread.
SysAdmin
It does. But delegate.BeginInvoke() has nothing to do with Control.BeginInvoke(), completely different methods.
Hans Passant
A: 

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.

Alex Farber
+1  A: 

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.

Hans Passant