3

A hard to track exception is occuring when non-UI threads try to Append their output to RichTextBox UI control in the Main Thread.

This exception occurs at random times, mostly when the threads are calling this method in quick succession. It occurs even in just 2 non-UI threads.

Below is the code of AppendLog method. It is in the Main UI's Form class. I spawn 2 threads and pass them this method as Action<string> logDelegate

I even have the syncobject in place.

  public void AppendLog(string message)
    {
        try
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<string>(this.AppendLog), message);
            }
            else
            {
                lock (_logSyncRoot)
                {

                    if (rtbLog.TextLength > 100000)
                        rtbLog.ResetText();

                    rtbLog.AppendText(message);
                    rtbLog.ScrollToCaret();
                }
            }
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
        }
    }

System.AccessViolationException : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

  at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
  at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
 at System.Windows.Forms.Control.DefWndProc(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.TextBoxBase.WndProc(Message& m)
at System.Windows.Forms.RichTextBox.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, Object& editOle)
at System.Windows.Forms.TextBoxBase.ScrollToCaret()
at MyApp.UI.OfflineAnalyzer.AppendLog(String message) in    D:\MyApp\Code\Charting\OfflineAnalyzer.cs:line 339
John Arlen
  • 6,539
  • 2
  • 33
  • 42
Munish Goyal
  • 1,379
  • 4
  • 27
  • 49
  • Try debugging with unmanaged debugging enabled to see the unmanged call stack as well (please right click on the call stack and press load symbols to get the symbols from MS servers). – Alois Kraus May 03 '12 at 20:03
  • @Alois It is hard to reproduce it at will. I will try what you said. – Munish Goyal May 03 '12 at 20:08
  • InvokeRequired can lead to wrong marshalling windows when you log something while the form window handle has not been created yet. Do you have log calls before the Form was visible? If yes try removing them to see if this resolves your problem. Does the exception appear on your main UI thread? What were the call stacks of the other threads? – Alois Kraus May 03 '12 at 20:10
  • @Alois No, the logging begins well after the form is created. The other analyzer threads start after user presses Start button. I will check and post the stacks of other threads. – Munish Goyal May 03 '12 at 20:15
  • Just a thought. Is it wrong to do this.InvokeRequired and this.Invoke. Should I be doing rtbLog.Invoke... ?? – Munish Goyal May 03 '12 at 20:18
  • @MunishGoyal As long as `this` is a control object created on the same thread as rtbLog, it's fine – John Arlen May 03 '12 at 20:27
  • ok so not an issue due to this . 'this' is the parent Form and rtbLog is child control in that form. – Munish Goyal May 03 '12 at 20:29

1 Answers1

1

The easiest situation in scenarios like this is to maintain a Queue<string> queue; if you have a list of messages for example. Add values to to the queue at will. In the main form thread, use a timer component and lock the queue while pulling out values e.g. lock (queue) {rtbLog.AppendText(queue.Dequeue());}.

Raheel Khan
  • 14,205
  • 13
  • 80
  • 168
  • good simple workaround. btw now only the main thread calls the actual rtb operation so probably this problem will not re-occur. – Munish Goyal May 12 '12 at 19:07
  • Tried this.with another timer method owned and run by main thread . with Q in common. Still problem occured while timer call to print the msgs in Q. again at accessing rtbLog control. – Munish Goyal May 12 '12 at 19:51
  • Could you post some code? Updating the RTB from a timer should not give you that issue at all. – Raheel Khan May 13 '12 at 05:38