Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从后台线程调用c#线程问题_C#_.net_Multithreading - Fatal编程技术网

从后台线程调用c#线程问题

从后台线程调用c#线程问题,c#,.net,multithreading,C#,.net,Multithreading,我有一个线程,它处理一些分析工作 private static void ThreadProc(object obj) { var grid = (DataGridView)obj; foreach (DataGridViewRow row in grid.Rows) { if (Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Val

我有一个线程,它处理一些分析工作

   private static void ThreadProc(object obj)
    {
        var grid = (DataGridView)obj;
        foreach (DataGridViewRow row in grid.Rows)
        {
            if (Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString()) != null)
                UpdateGridSafe(grid,row.Index,1);
            Thread.Sleep(10);
        }
    }
我想在loop安全地更新我的gridView,所以我使用经典方式:

    private delegate void UpdateGridDelegate(DataGridView grid, int rowIdx, int type);
    public static void UpdateGridSafe(DataGridView grid, int rowIdx, int type)
    {
        if (grid.InvokeRequired)
        {
            grid.Invoke(new UpdateGridDelegate(UpdateGridSafe), new object[] { grid, rowIdx, type });
        }
        else
        {
            if (type == 1)
                grid.Rows[rowIdx].Cells["Prep"].Style.ForeColor = Color.Red;
            if (type==2)
                grid.Rows[rowIdx].Cells["Prep"].Style.ForeColor = Color.ForestGreen;

        }
    }
但当我进入UpdateGridSafe时,程序挂起

在调试器中,我看到grid.Invoke没有调用UpdateGridSafe。请帮忙-怎么了

编辑

经典线程创建代码

        Thread t = new Thread(new ParameterizedThreadStart(ThreadProc));
        t.Start(dgvSource);
        t.Join();
        MessageBox.Show("Done", "Info");

Invoke语句将等待主线程的消息泵不忙,并且可以处理新消息。如果主线程正忙,调用将挂起

在您的例子中,您的顶层代码似乎在一个紧密的循环中运行,因此底层代码中的调用永远不可能真正运行。如果您将上层代码块中的Thread.Sleep更改为某个有时间的代码块,希望这会给您的主线程一个处理.Invoke调用的机会


根据您的主应用程序线程正在执行的操作,您可能需要在运行任何.Invoke调用之前实际完成第一个循环-如果是这种情况,我可以发布一些修改过的代码,这些代码可能会更好。

永远不要每次使用线程。Sleep(0)。它不会做你认为它会做的事,只会给你带来痛苦。例如,在一个紧循环中,操作系统可能会决定刚刚休眠的线程是下一个要运行的线程。因此,您实际上不会产生线程

使用Thread.Sleep(1)每N次迭代重试一次代码,其中N大约是0.25到1.0秒的工作量

如果这不起作用,请告诉我,我们可以看看ThreadProc是如何创建的

参考资料

编辑

从不使用线程睡眠的理由


这是因为您正在加入工作线程。UI线程启动后台线程,然后对其调用Join。这将停止UI线程执行任何其他操作

在此期间,后台线程正在执行其工作并调用Invoke,它将等待UI线程响应。因为UI线程正在等待连接,所以它永远不会处理要调用的请求。因此,僵局

您应该做的是删除Join和MessageBox。将MessageBox放入它自己的函数中

void NotifyDone() {
    if( InvokeRequired ) BeginInvoke( (MethodInvoker) NotifyDone );
    else {
        // Perform any post-processing work
        MessageBox.Show("Done", "Info");  
    }
}
后台线程完成后,只需调用此方法(并从ThreadProc中消除static)


正如其他人已经说过的,睡眠的使用,特别是在如此低的间隔时间,要么是危险的,误导的,要么是毫无价值的。我在“数一数二”阵营。

你陷入了僵局。您的t.Join正在阻止GUI线程,直到ThreadProc完成。ThreadProc在等待t.Join完成时被阻塞,因此它可以执行调用

错误代码

    Thread t = new Thread(new ParameterizedThreadStart(ThreadProc)); 
    t.Start(dgvSource); 
    t.Join();  <--- DEADLOCK YOUR PROGRAM
    MessageBox.Show("Done", "Info"); 
编辑

也可以使用BeginInvoke而不是Invoke。这样,您的工作线程就不必在每次更新GUI时都阻塞

参考文献


从不同线程同时访问网格时也可能遇到问题。DataTables不是线程安全的,所以我猜DataGridView也不是。下面是一些示例代码,您可以在其中使用Monitor.Enter和Montori.Exit来获得一些并发性

    public void DoWorkUpdatingRow(object state)
    {
        List<DataRow> rowsToWorkOn = (List<DataRow>)state;
        foreach (DataRow dr in rowsToWorkOn)
        {
            Monitor.Enter(this);
            try
            {
                dr["value"] = dr["id"] + " new value";
            }
            finally
            {
                Monitor.Exit(this);
            }
        }
    }
public void doworkUpdatengRow(对象状态)
{
List rowsToWorkOn=(列表)状态;
foreach(rowsToWorkOn中的数据行dr)
{
监视。输入(此);
尝试
{
dr[“value”]=dr[“id”]+新值;
}
最后
{
监控。退出(本);
}
}
}

我改为线程睡眠(10);但情况也一样:(.Main-app-thread是ui-thread。不工作。请发布可能工作得更好的代码。@Andrew-如果第一个代码块中的主线程是您的ui-thread,并且您在一个紧密循环中运行它,那么它将不会响应任何请求。调用请求,直到它处理完您正在运行的forEach中的每一行。如果您正在调用adProc()不过,在另一个线程上,您的消息泵应该是可用的,.Invoke挂起的事实表明您正在阻止主UI线程。找出主线程暂停的位置并解决该问题,然后,.Invoke调用将再次开始工作。我从主thrad创建ThreadProc,用于处理后面的一些工作ground@Andrew:您的编辑会将其清除。.Join会导致您的UI线程等待新线程以继续,这意味着当您的辅助线程尝试调用时,它会很忙。对它进行调用。为什么需要加入它?只需等待您创建的线程完成,然后引发一个事件,您可以在UI线程上处理该事件播放你的messagebox。谢谢你的回答。我尝试设置睡眠时间,但没有帮助。我还添加了一些代码来发布。为什么要使用thread.Sleep?如果你想在更新网格后执行任何操作,你可以在这里使用回调函数吗?
   backgroundWorker1.RunWorkerAsync

  private void backgroundWorker1_DoWork(object sender, 
        DoWorkEventArgs e)
    {    
        var grid = (DataGridView)obj;    
        foreach (DataGridViewRow row in grid.Rows)    
        {    
            if (Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString()) != null)    
                UpdateGridSafe(grid,row.Index,1);    
            // don't need this Thread.Sleep(10);    
        }    
    }  

   private void backgroundWorker1_RunWorkerCompleted(
            object sender, RunWorkerCompletedEventArgs e)
        {
        MessageBox.Show("Done", "Info"); 
}
    public void DoWorkUpdatingRow(object state)
    {
        List<DataRow> rowsToWorkOn = (List<DataRow>)state;
        foreach (DataRow dr in rowsToWorkOn)
        {
            Monitor.Enter(this);
            try
            {
                dr["value"] = dr["id"] + " new value";
            }
            finally
            {
                Monitor.Exit(this);
            }
        }
    }