如何让UI线程等待信号量,但处理其他调度程序请求?(就像MessageBox.Show本身一样)通常,当UI线程调用MessageBox.Show()之类的东西时,当前代码不会继续执行,直到用户单击确定,但程序会继续运行其他代码。在这个问题中,我遇到了一个问题,即在对UI线程的一次调用中分派了太多的委托。我想在继续执行之前在某些点暂停。在我的新错误处理程序中,我使用信号量来确保一次只处理一个错误。我发送一个MessageBox来提醒用户,当他们单击“确定”时,我释放信号量,允许处理下一个错误。问题是它没有按预期工作。如果同时发生对HandleError的两次调度调用,则第一次调用MessageBox.Show,第二次调用UI线程。奇怪的是,从未执行对MessageBox.Show()的调度调用——整个应用程序只是挂起——因此当用户单击“确定”时应该释放的信号量被永久锁定。这个解决方案缺少什么?privatestaticConcurrentDictionaryQueuedErrors=newConcurrentDictionary();私有静态信号量Lock_HandleError=newSemaphore(1,1);//一次只能处理一个ErrorprivatestaticvoidErrorHandled(Exceptionex){DateTimevalue;QueuedErrors.TryRemove(例如,输出值);Lock_HandleError.Release();}privatestaticboolExceptionHandlingTerminated=false;publicstaticvoidHandleError(Exceptionex,stringextraInfo="",boolshowMsgBox=true,boolresetApplication=true){if(ExceptionHandlingTerminated||App.Current==null)返回;QueuedErrors.TryAdd(例如,DateTime.Now);//线程安全跟踪同时抛出多少错误Lock_HandleError.WaitOne();//这将确保一次只处理一个错误。如果(ExceptionHandlingTerminated||App.Current==null){ErrorHandled(ex);返回;}try{if(QueuedErrors.Count>10){ExceptionHandlingTerminated=true;抛出新异常n("后台同时抛出太多错误。");}if(Thread.CurrentThread!=Dispatcher.CurrentDispatcher.Thread){//我们不在UI线程上,我们必须调度这个调用。((App)App.Current).Dispatcher.BeginInvoke((Action)delegate(Exception_ex,string_extraInfo,bool_showMsgBox,bool_resetApplication){ErrorHandled(_ex);//释放生成的HandleError调用HandleError(_ex,_extraInfo,_showMsgBox,_resetApplication);},DispatcherPriority.Background,newobject[]{ex,extraInfo,showMsgBox,resetApplication});返回;}if(showMsgBox){//如果UI正在处理可视树事件(例如IsVisibleChanged),它会在显示MessageBox时抛出异常,如下所述:http://social.msdn.microsoft.com/forums/en-US/wpf/thread/44962927-006e-4629-9aa3-100357861442//解决方法是对MessageBox进行派发和排队。我们必须使用BeginInvoke,因为调度程序处理暂停在这种情况下结束。Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate(Exception_ex,String_ErrMessage){MessageBox.Show(_ErrMessage,"MUSApplicationError",MessageBoxButton.OK,MessageBoxImage.Error);ErrorHandled(_ex);//释放占用的信号量通过生成HandleError调用},DispatcherPriority.Background,newobject[]{ex,extraInfo});}else{ErrorHandled(ex);}}catch(异常终止错误){ExceptionHandlingTerminated=true;Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate(String_fatalMessage){MessageBox.Show(_fatalMessage,"致命错误",MessageBoxButton.OK,MessageBoxImage.Stop);if(App.Current!=null)App.Current.Shutdown(1);},DispatcherPriority.Background,newobject[]{fatalMessage});错误处理(例如);//释放此HandleError调用占用的信号量,这将允许所有其他排队的HandleError调用继续并检查ExceptionHandlingTerminated标志。}}不要担心奇怪的丢掉消息符字符串,我删除了很多细节以使模式更清晰blocking队列事件源调用后台线程上的委托到“ProcessQueue”“ProcessQueue”委托获取锁(就像您所做的那样),使消息出队,并调用(同步)UI线程来显示消息。然后它循环,做同样的事情直到队列为空。所以像这样(未经测试的代码):privatestaticConcurrentQueue>QueuedErrors=newConcurrentQueue>();私有静态对象Lock_HandleError=newObject();publicstaticvoidHandleError(Exceptionex,stringextraInfo="",boolshowMsgBox=true,boolresetApplication=true){QueuedErrors.Enqueue(newTuple(ex,DateTime.Now));ThreadPool.QueueUserWorkItem(()=>((App)App.Current).Dispatcher.Invoke((Action)()=>{lock(Lock_HandleError)TuplecurrentEx;while(QueuedErrors.TryDequeue(outcurrentEx))MessageBox.Show(currentEx.Item1,//异常“MUS应用程序错误”,MessageBoxButton.OK,MessageBoxImage.Error);})));我决定按照建议将它们存储在一个集合中。我只是按顺序处理错误,然后从堆栈中弹出一个新错误(如果有的话)。如果堆栈上有太多错误,那么我假设我们处于级联错误状态,我将错误汇总在一条消息中并关闭应用程序。以上是C#学习教程:如何让UI线程等待信号量,但处理其他调度器请求?(和MessageBox.Show本身一样)所有分享的内容,如果对你有用,需要了解更多C#学习教程,希望大家多多关注—privatestaticConcurrentStack>ErrorStack=newConcurrentStack>();privatestaticboolExceptionHandlingTerminated=false;私有静态布尔ErrorBeingHandled=false;//一次只能处理一个ErrorpublicstaticvoidHandleError(Exceptionex,boolshowMsgBox){HandleError(ex,"",showMsgBox,true);}publicstaticHandleError(Exceptionex,stringextraInfo,boolshowMsgBox){HandleError(ex,extraInfo,showMsgBox,true);}publicstaticvoidHandleError(Exceptionex,stringextraInfo="",boolshowMsgBox=true,boolresetApplicationif){(ExceptionHandlingTerminated||App.Current==null)return;if(ErrorBeingHandled){//排队这个错误,稍后处理。如果我们已经排队超过10个错误,请不要担心,无论如何,我们将在这种情况下终止应用程序。如果(ErrorStack.Count(DateTime.Now,ex,extraInfo,showMsgBox,resetApplication));//线程安全跟踪同时抛出多少错误返回;}ErrorBeingHandled=true;try{if(Thread.CurrentThread!=Dispatcher.CurrentDispatcher.Thread){ErrorBeingHandled=false;Invoke_HandleError(ex,extraInfo,showMsgBox,resetApplication);返回;}if(ErrorStack.Count>=5){ExceptionHandlingTerminated=true;元组错误参数;StringerrQueue=String.Concat(DateTime.Now.ToString("hh:mm:ss.fftt"),":",ex.Message,"n");while(ErrorStack.Count>0){if(ErrorStack.TryPop(outerrParams)){errQueue+=String.Concat(errParams.Item1.ToString("hh:mm:ss.fftt"),":",errParams.Item2.Message,"n");}}extraInfo="在后台抛出了太多同时发生的错误:";抛出新的异常(errQueue);}if(!((App)App.Current).AppStartupComplete){//如果应用程序尚未启动,我们无法以正常方式处理错误.extraInfo="应用程序启动前发生错误。"+额外信息;扔前;}if(resetApplication){((MUSUI.App)App.Current).ResetApplication();}if(showMsgBox){//(removed)...PrepareErrormessage//如果UI正在处理可视树事件(例如IsVisibleChanged),它会在显示MessageBox时抛出异常,如下所述:http://social.msdn.microsoft.com/forums/en-US/wpf/thread/44962927-006e-4629-9aa3-100357861442//解决方案是调度和排队MessageBox。我们必须使用BeginInvoke,因为在这种情况下调度程序处理会暂停。Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate(Exception_ex,String_ErrMessage){MessageBox.Show(App.Current.MainWindow,_ErrMessage,"MUS应用程序错误",MessageBoxButton.OK,MessageBoxImage.Error);ErrorHandled(_ex);//释放HandleError方法上的块并处理任何其他排队的错误。},DispatcherPriority.Background,newobject[]{例如,ErrMessage});}else{ErrorHandled(ex);}}catch(异常终止错误){ExceptionHandlingTerminated=true;//发生了一个非常严重的错误,比如应用程序没有加载,我们必须关闭。Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate(String_fatalMessage){MessageBox.Show(_fatalMessage,"致命错误",MessageBoxButton.OK,MessageBoxImage.Stop);if(App.Current!=null)App.Current.Shutdown(1);},DispatcherPriority.Background,newobject[]{fatalMessage+"n"+terminatingError.Message});}}//错误处理完成后要执行的操作集。privatestaticvoidErrorHandled(Exceptionex){ErrorBeingHandled=false;//如果在处理这个错误后其他错误已经排队,或者仍然存在,则处理下一个错误if(ErrorStack.Count>0){if(ExceptionHandlingTerminated||App.Current==null)return;元组错误参数;//从队列中弹出一个错误并处理它:EerrorStack.TryPop(outerrParams);HandleError(errParams.Item2,errParams.Item3,errParams.Item4,errParams.Item5);}}//在UI线程上调度对HandleError的调用。privatestaticvoidInvokeex_HandletionError(ExceptionextraInfo,boolshowMsgBox,boolresetApplication){((App)App.Current).Dispatcher.BeginInvoke((Action)delegate(Exception_ex,string_extraInfo,bool_showMsgBox,bool_resetApplication){错误处理(_ex);//释放由生成的HandleError调用获取的信号量侵权请点击维权联系管理员删除如需转载请注明出处:
