【问题标题】:Winforms: Attempted to read or write protected memory. This is often an indication that other memory is corruptWinforms:试图读取或写入受保护的内存。这通常表明其他内存已损坏
【发布时间】:2012-06-27 03:36:55
【问题描述】:

我有一堆背景事件。

他们都调用了一个日志:

private void log(string text, params object[] values)
{
    if (editLog.InvokeRequired)
    {
        editLog.BeginInvoke(
            (MethodInvoker)delegate
            {
                this.log(text, values);
            });
    }
    else
    {
        text = string.Format(text, values) + Environment.NewLine;

        lock (editLog)
        {
            editLog.AppendText(text);
            editLog.SelectionStart = editLog.TextLength;
            editLog.ScrollToCaret();               
        }
    }
}

有时我会得到这个,但有时不会:

System.AccessViolationException was unhandled
  Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  Source=System.Windows.Forms
  StackTrace:
       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.WndProc(Message& m)
       at System.Windows.Forms.RichTextBox.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 Program1.frmMain.log(String text, Object[] values) in 
       ...
       ...
       ...

P.D:并不总是停在这一行,随机将是使用 editLog 方法/属性的三次之一。并不总是抛出异常。有时看起来像东西冻结。但不是主 UI,只是消息流(即:日志看起来不再被调用)

该应用程序是一个单一的窗体,具有后台进程。我看不出我做错了什么......

更新

我按照 Mangist 的建议,这是代码(定时器在 100 毫秒触发)。结果相同:

private Queue<String> logs = new Queue<String>();
private void timerLog_Tick(object sender, EventArgs e)
{
    lock (logs)
    {
        for (int i = 0; i < logs.Count; i++)
        {
            editLog.AppendText(logs.Dequeue());
            editLog.SelectionStart = editLog.TextLength;
            editLog.ScrollToCaret();
        }             
    }
}

private void log(string text, params object[] values)
{
    text = string.Format(text, values) + Environment.NewLine;

    if (editLog.InvokeRequired)
    {
        editLog.BeginInvoke(
            (MethodInvoker)delegate
            {
                lock (logs)
                {
                    logs.Enqueue(text);
                }
                //this.log(text, values);
            });
    }
    else
    {
        logs.Enqueue(text);
    }
}

【问题讨论】:

  • 在 UI 线程中锁定控件的目的是什么?消息泵已经保证您可以单线程访问。
  • 嗯,那把锁在我看来纯属猜测......
  • 一般规则:从不锁定真实对象(例如this)。始终使用 new object() 成员仅用于锁定。见Why the Great Idea isn't So Great

标签: .net winforms multithreading visual-studio-2008 .net-4.0


【解决方案1】:

如果日志记录启动非常快(在创建表单句柄之前),就会发生这种情况。在调用控件上的任何方法之前检查editLog.IsHandleCreated == true。这会有所帮助,否则请使用线程安全的 Queue&lt;string&gt;(被 lock (obj) {} 语句包围)并在表单中放置一个计时器,以定期读取此队列以获取新日志。

【讨论】:

  • 我都实现了,但仍然遇到同样的问题。
  • 在附加文本之前添加对 editLog.IsHandleCreated == true 的检查。
  • 还是同样的问题。甚至 GUI 冻结 :(
【解决方案2】:

嗯,终于找到问题了。删除它可以消除问题(并使用正常的 BeginInvoke,没有技巧、锁等):

editLog.SelectionStart = editLog.TextLength;
editLog.ScrollToCaret();

我尝试使用http://nlog-project.org/,我的第一次尝试工作完全正常(使用http://nlog-project.org/wiki/RichTextBox_target)。当我设置autoScroll="true" 时,再次得到同样的错误。这就是我发现问题的方式。

【讨论】:

    猜你喜欢
    • 2011-07-13
    • 2010-10-27
    • 2011-05-26
    • 2011-03-11
    • 2014-04-30
    • 2016-10-23
    • 1970-01-01
    • 1970-01-01
    • 2013-01-23
    相关资源
    最近更新 更多