Попытка чтения или записи защищенной памяти.Это часто указывает на то, что другая память повреждена - PullRequest
7 голосов
/ 02 апреля 2012

Я действительно не понимаю, как эта ошибка происходит в этом коде.Пожалуйста, проверьте код самостоятельно

    void dispatcherTimer_Tick(object sender, EventArgs e)
{
    string srUrl = lstLocalIndex[irLocalIndex] + lstMainIndex[irMainIndex].Replace("0;","");

    Task.Factory.StartNew(() =>
    {
        startNewWindow(srUrl);
    });

}


    void startNewWindow(string srUrl)
{
    NewWindowThread<TitleWindow, string>(c => new TitleWindow(c), srUrl);
}

Теперь в этом коде происходит ошибка.Я также приложу снимок экрана

        private void NewWindowThread<T, P>(Func<P, T> constructor, P param) where T : Window
    {
        Thread thread = new Thread(() =>
        {
            T w = constructor(param);
            w.Show();
            w.Closed += (sender, e) => w.Dispatcher.InvokeShutdown();
            try
            {
                System.Windows.Threading.Dispatcher.Run();
            }
            catch
            {

            }
        });
        thread.SetApartmentState(ApartmentState.STA);
        try
        {
            thread.Start();
        }
        catch
        {

        }
    }

Эта ошибка вызывает ошибку сброса всего программного обеспечения и перестает работать, даже если я вызываю их в новом потоке: (

Ошибка сброса этой строки Система.Windows.Threading.Dispatcher.Run ();

Пожалуйста, проверьте также скриншот

enter image description here

C # 4.0 WPF

Ответы [ 3 ]

2 голосов
/ 08 августа 2013

Я боролся с этой проблемой с клиентом, и вот что я нашел.

Мы работаем над приложением WPF, которое выполняет многопоточную и фоновую обработку.Это исключение внезапно начало появляться, и я начал кое-что копать.Наконец, я нашел виновника примерно через час расследования:

        var worker = new BackgroundWorker();
        worker.DoWork += (o, ea) => Dispatcher.BeginInvoke(new Action(() =>
        {
            //do some heavy processing here, plus UI work, then call another method.

            //inside that other method, I found this:
            var thread = new Thread(() =>
            {
                //do some heavy processing.
            }) { IsBackground = true };
            thread.Start();
        }));

Похоже, что происходило то, что фоновый работник заканчивает свою работу и возвращается из своей работы.Однако поток, созданный внутри этого фонового работника, не завершил обработку и возвращается только для того, чтобы обнаружить, что поток, в котором он был создан, уже вышел из области видимости, в результате чего возникла исключительная ситуация AccessViolationException.

Для того, чтобыОтладив это, я бы посоветовал обратить пристальное внимание на то, где происходит исключение, и внимательно изучить ваш стек вызовов, который может быть, а может и не быть уничтожен или потерян, в зависимости от того, находитесь ли вы в потоке, когда возникает исключение.

1 голос
/ 02 апреля 2012

У меня была похожая проблема некоторое время назад.

Ошибка возникает из-за того, что ваше окно выходит из области видимости, а сборщик мусора уничтожает его.

Использование ShowDialog() должно решить проблему. Обратите внимание, что это не будет блокировать другие потоки, потому что окно будет модальным только в вызывающем потоке.

private void NewWindowThread<T, P>(Func<P, T> constructor, P param) where T : Window
{
    Thread thread = new Thread(() =>
    {
        System.Windows.Threading.Dispatcher.Run();
        T w = constructor(param);
        w.ShowDialog();
        w.Dispatcher.InvokeShutdown();
    });
    thread.SetApartmentState(ApartmentState.STA);
    try
    {
        thread.Start();
    }
    catch
    {
        // log&handle exceptions
    }
}
0 голосов
/ 03 апреля 2012

Вы используете лямбду в качестве функции потока. Эта лямбда вызывается в новом потоке. На В момент, когда поток действительно создан, он будет искать заданный вами аргумент, который является локальной переменной srUrl, но к тому времени, когда это произойдет, ваша функция (dispatcherTimer_Tick) уже вышла, поэтому srUrl будет в той части стека, которая больше не определяется должным образом (отсюда нарушение доступа). Простое решение - определить переменную в классе и быстро заполнить srLoc. Более правильное решение - фактически передать srLoc в качестве аргумента:

() =>
{
    startNewWindow(srUrl);
}

становится

(Action<string>){x => {startNewWindow(x);},
            new object[] {srUrl}

Теперь ссылка на функцию и правильная копия строки сохраняются для вызова функции, и не имеет значения, что исходный srUrl выходит из области действия к тому времени, когда поток запускается. Я не уверен, что фабрика задач позволяет передавать массив аргументов. диспетчеры обычно имеют для этого перегрузку, поэтому, возможно, вы захотите, чтобы ваше окно позаботилось об этом.

Теперь вы на самом деле делаете это несколько раз, поэтому вам может понадобиться оборачивать аргументы каждый раз, когда они передаются.

...