Winforms: Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена

У меня есть куча фоновых событий.

Все они вызывают лог:

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 
       ...
       ...
       ...

PD: Не всегда останавливайтесь на этой строке, случайным образом будет один из трех случаев использования методов/свойств editLog. Не всегда исключением является throw. Иногда кажется, что вещь замирает. Но не основной пользовательский интерфейс, а просто поток сообщений (то есть: журнал выглядит так, как будто больше никогда не вызывается)

Приложение представляет собой единую форму с фоновым процессом. Я не вижу, что я делаю неправильно с этим ...

ОБНОВЛЕНИЕ:

Я делаю предложение Мангиста, это код (таймер срабатывает на 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);
    }
}

person mamcx    schedule 25.06.2012    source источник
comment
Какова цель блокировки элемента управления в потоке пользовательского интерфейса? Помпа сообщений уже гарантирует доступ к одному потоку.   -  person Remus Rusanu    schedule 26.06.2012
comment
Ну, этот замок был чистой догадкой с моей стороны...   -  person mamcx    schedule 26.06.2012
comment
Общее правило: никогда не блокируйте реальный объект (например, this). Всегда используйте элемент new object() только для блокировки. См. Почему великая идея не так велика.   -  person Remus Rusanu    schedule 26.06.2012


Ответы (2)


Это может произойти, если логирование запускается очень быстро (до создания дескриптора формы). Проверьте наличие editLog.IsHandleCreated == true перед вызовом каких-либо методов элемента управления. Это может помочь, в противном случае используйте потокобезопасный Queue<string> (окруженный оператором lock (obj) {}) и поместите таймер в свою форму, чтобы периодически читать эту очередь для новых журналов.

person Jon    schedule 25.06.2012
comment
Я реализую оба и все еще получаю ту же проблему. - person mamcx; 26.06.2012
comment
Добавьте проверку для editLog.IsHandleCreated == true перед добавлением текста. - person Jon; 26.06.2012
comment
Все та же проблема. Даже графический интерфейс зависает :( - person mamcx; 26.06.2012

Ну наконец нашел проблему. Удаление этого устраняет проблему (и работает с обычным BeginInvoke, без трюков, блокировок и прочего):

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

Я пытаюсь использовать http://nlog-project.org/, и моя первая попытка работает полностью нормально (с http://nlog-project.org/wiki/RichTextBox_target). Когда я устанавливаю autoScroll="true", снова получаю ту же ошибку. Вот как я нахожу проблему.

person mamcx    schedule 26.06.2012