7

我真的不明白这个错误是如何发生在这段代码上的。请检查代码自己试图读取或写入受保护的内存。这通常表明其他内存已损坏

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。运行();

请检查还截图

enter image description here

C#4.0 WPF

+0

实际上,您使用*两个*线程,即Task中的线程,然后是Thread线程,最好将您想要作为启动代码运行的代码放在Thread中。 – casperOne 2012-04-02 19:40:19

+0

@casperOne我也试过这个应用程序崩溃。过了一段时间后,这种情况不会立即发生。它运行30分钟然后崩溃。崩溃时间改变。 – MonsterMMORPG 2012-04-02 19:41:53

+0

不,他们说你的记忆被打破了。它一定是如此! (顺便说一句,这是我遇到'未指定的错误'后遇到的最愚蠢的错误消息)。 – leppie 2012-04-02 19:53:02

回答

0

您正在使用lambda作为线程函数。这个lambda在新线程上被调用。在实际创建线程的 时刻,它将查找您提供的参数,该参数是一个局部变量srUrl,但到这种情况发生时,您的函数(dispatcherTimer_Tick)已经退出,因此srUrl将处于堆栈不再正确定义(因此访问冲突)。简单的解决方法是在类中定义一个变量并快速填充srLoc。更合适的解决方案是实际传递srLoc作为参数:

() => 
{ 
    startNewWindow(srUrl); 
} 

成为

​​

现在函数引用和字符串的正确副本被保存为函数调用,并且它不”不管线程开始时,原始的srUrl超出了范围。我不确定任务工厂是否允许传递参数数组。调度员通常对此有重载,所以也许你想让你的窗口照顾这一点。

现在你实际上做了几次,所以你可能需要在每次传递参数时包装参数。

+0

感谢您的回答。其实我通过编写另一个从文件中读取url的应用程序来解决我的问题。所以我现在开始exes而不是新窗口。有些时候这些新的错误提供了错误,但软件继续运行:)但你的答案是非常专业的,我喜欢它。 – MonsterMMORPG 2012-04-03 13:51:07

+1

@MonsterMMORPG这个答案听起来很合理,但它是错误的。闭包将捕获局部变量(称为自由变量)。另请参阅:http://www.codethinked.com/c-closures-explained – ChrisWue 2012-04-03 19:53:33

+0

如果这是真的,那么即使显示窗口,您的代码也会中断。显示窗口后,srUrl未被使用。 – surfen 2012-04-03 20:21:57

1

前段时间我有类似的问题。

发生此错误是因为您的窗口超出了范围,并且垃圾收集器将其销毁。

使用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

如果为true ...您可以通过在加载的事件中设置事件并在退出代理之前等待该事件来做类似事情。 – Yaur 2012-04-02 20:14:21

+0

这是有道理的,但不会阻止新创建的窗口的用户界面? – surfen 2012-04-02 20:21:42

+0

谢谢你的回答。现在就去尝试。 – MonsterMMORPG 2012-04-02 21:23:32

2

我一直在与客户作战,这是我发现的问题。

我们正在开发一个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。

为了调试这个,我建议密切关注发生异常的地方并仔细检查你的调用堆栈,它可能已经被破坏或丢失,这取决于你是否在线程中抛出异常。

相关问题