Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена
Я действительно не понимаю, как эта ошибка происходит в этом коде. Пожалуйста, проверьте код самостоятельно
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
{
}
}
Эта ошибка вызывает ошибку программного сброса и перестает работать, хотя я вызываю их в новом потоке:(
В этой строке выдается ошибка System.Windows.Threading.Dispatcher.Run();
Пожалуйста, проверьте также скриншот
C# 4.0 WPF
3 ответа
Вы используете лямбду в качестве функции потока. Эта лямбда вызывается в новом потоке. В тот момент, когда поток действительно создан, он будет искать заданный вами аргумент, который является локальной переменной srUrl, но к тому времени, когда это произойдет, ваша функция (dispatcherTimer_Tick) уже вышла, поэтому srUrl будет в части стека. это больше не определяется должным образом (отсюда и нарушение прав доступа). Простое решение - определить переменную в классе и быстро заполнить srLoc. Более правильное решение - фактически передать srLoc в качестве аргумента:
() =>
{
startNewWindow(srUrl);
}
становится
(Action<string>){x => {startNewWindow(x);},
new object[] {srUrl}
Теперь ссылка на функцию и правильная копия строки сохраняются для вызова функции, и не имеет значения, что исходный srUrl выходит из области действия к моменту запуска потока. Я не уверен, позволяет ли фабрика задач массив аргументов для передачи. диспетчеры обычно имеют для этого перегрузку, поэтому, возможно, вы захотите, чтобы ваше окно позаботилось об этом.
Теперь вы на самом деле делаете это несколько раз, поэтому вам может понадобиться оборачивать аргументы каждый раз, когда они передаются.
Я боролся с этой проблемой с клиентом, и вот что я нашел.
Мы работаем над приложением 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.
Чтобы отладить это, я бы посоветовал обратить пристальное внимание на то, где происходит исключение, и внимательно изучить ваш стек вызовов, который мог или не мог быть уничтожен или потерян, в зависимости от того, находитесь ли вы в потоке, когда возникает исключение.
У меня была похожая проблема некоторое время назад.
Ошибка возникает из-за того, что ваше окно выходит из области видимости, а сборщик мусора уничтожает его.
С помощью 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
}
}