c#使用后台线程调用的线程问题我有线程,它处理一些分析工作。privatestaticvoidThreadProc(objectobj){vargrid=(DataGridView)obj;foreach(DataGridViewRowrowingrid.Rows){if(Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString())!=null)UpdateGridSafe(grid,row.Index,1);线程.睡眠(10);我想在一个循环中安全地更新我的gridView,所以我使用经典的方式:privatedelegatevoidUpdateGridDelegate(DataGridViewgrid,introwIdx,inttype);publicstaticvoidUpdateGridSafe(DataGridViewgrid,introwIdx,inttype){if(grid.InvokeRequired){grid.Invoke(newUpdateGridDelegate(UpdateGridSafe),newobject[]{grid,rowIdx,type});}else{if(type==1)grid.Rows[rowIdx].Cells["Prep"].Style.ForeColor=Color.Red;如果(type==2)grid.Rows[rowIdx].Cells["Prep"].Style.ForeColor=Color.ForestGreen;但是当我进入UpdateGridSafe时,程序挂起。在调试器中,我看到grid.Invoke没有调用UpdateGridSafe。请帮忙-怎么了?编辑经典线程创建代码Threadt=newThread(newParameterizedThreadStart(ThreadProc));t.开始(dgvSource);t.Join();MessageBox.Show("完成","信息");你有一个僵局。您的t.Join会阻塞GUI线程,直到ThreadProc完成。ThreadProc被阻塞等待t.Join完成,因此它可以执行调用。错误代码Threadt=newThread(newParameterizedThreadStart(ThreadProc));t.开始(dgvSource);t.Join();好的代码backgroundWorker1.RunWorkerAsyncprivatevoidbackgroundWorker1_DoWork(objectsender,DoWorkEventArgse){foreach(DataGridViewRowrowingrid.Rows){if(Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString())!=null)UpdateGridSafe(grid,row.Index,1);//不需要这个Thread.Sleep(10);}}privatevoidbackgroundWorker1_RunWorkerCompleted(objectsender,RunWorkerCompletedEventArgse){MessageBox.Show("Done","Info");编辑也使用BeginInvoke而不是Invoke。这样,工作线程就不必在每次更新GUI时都阻塞。参考避免Invoke(),更喜欢BeginInvoke()这是因为你加入了你的工作线程。您的UI线程启动后台线程,然后调用Join。这会阻止UI线程执行任何其他操作。在此期间,后台线程正在执行其工作并调用Invoke,后者等待UI线程响应。因为UI线程正在等待Join,所以不会处理调用的请求。因此,僵局。您应该做的是消除Join和MessageBox。将MessageBox放入它自己的函数中。voidNotifyDone(){if(InvokeRequired)BeginInvoke((MethodInvoker)NotifyDone);else{//执行任何后处理工作MessageBox.Show("Done","Info");当后台线程完成时,只需调用此方法(并从ThreadProc中消除静态)。privatevoidThreadProc(objectobj){vargrid=(DataGridView)obj;foreach(DataGridViewRowrowingrid.Rows){if(Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString())!=null)UpdateGridSafe(grid,row.Index,1);线程.睡眠(10);}NotifyDone();正如其他人已经说过的那样,睡眠的使用,尤其是在如此短的间隔内,要么是危险的、误导性的,要么是毫无价值的。我是一个毫无价值的营地。Invoke语句会一直等到主线程的消息泵不忙并且可以处理新消息。如果主线程忙,Invoke就会挂起。在您的情况下,您的顶级代码似乎在紧密循环中运行,因此底层代码中的Invoke永远无法真正运行。如果您将上面代码块中的Thread.Sleep更改为有时间的东西,希望这将使您的主线程有机会处理.Invoke调用。根据您的主应用程序线程正在做什么,您可能需要在任何.Invoke调用运行之前实际完成第一个循环-如果是这种情况,我可以发布一些可能工作得更好的修改代码。从不,总是使用Thread.Sleep(0)。它并没有像您认为的那样做,只会给您带来痛苦。例如,在紧密循环中,操作系统可以决定刚刚休眠的线程是下一个要运行的线程。所以你实际上并没有产生线程。每N次迭代使用Thread.Sleep(1)再次尝试您的代码,其中N大约为0.25到1.0秒。如果这不起作用,请告诉我,我们可以看到ThreadProc是如何创建的。在无限循环中参考永远不要睡眠(0)您可能还会遇到从不同线程并发访问网格的问题。DataTables不是线程安全的,所以我猜DataGridView也不是。下面是这篇关于DataRow和并发性的文章中的一些示例代码,您可以使用Monitor.Enter和Montori.Exit来获得一些并发性。以上就是C#学习教程的全部内容:c#使用后台线程调用的线程问题分享。如果对大家有用,需要详细了解C#学习教程,希望大家多多关注---publicvoidDoWorkUpdatingRow(objectstate){ListrowsToWorkOn=(List)state;foreach(DataRowdrinrowsToWorkOn){Monitor.Enter(this);try{dr["value"]=dr["id"]+"新值";}最后{监视器。退出(这个);}}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
