线程和等待

时间:2010-02-08 12:40:11

标签: c# multithreading

我有一个线程,它从网站收集一个URL列表,并在这样做时更新UI。这很好。但是,我需要主线程等待直到收集链接。我尝试进行连接,但这会锁定UI。这是我的例子。正如您所看到的那样,在线程运行的同时调用foreach循环。我希望foreach在线程运行后运行。

有什么想法吗?

/** This thread will add links to list<string> linkList **/
Thread linkListThread = new Thread(new ThreadStart(getLinkList));
linkListThread.Start();
foreach (String link in linkList)
{
    txtOutput.Text += link;
}

6 个答案:

答案 0 :(得分:6)

您可以使用后台工作人员。或者让线程方法在完成后在主上下文中调用方法,传递您收集的项目列表。

修改
我想我应该稍微详细说明我的第二种方法。

您可以在创建线程之前准备列表实例:

List<string> links = new List<string>();

然后将此列表传递给填充它的线程:

Thread t = new Thread(new ParameterizedThreadStart(FillList));
t.Start(links);

线程方法获取列表,填充它并调用显示UI中详细信息的方法:

private static void FillList(object state)
{
    List<string> links = (List<string>)state;

    // Fill data

    this.Invoke((MethodInvoker)delegate() { HandleNewLinks(links); }));
}

HandleNewLinks方法可以正常运行:

private void HandleNewLinks(List<string> links)
{
    foreach (string link in links)
        // Do something...
}

答案 1 :(得分:1)

将线程完成后需要运行的代码移动到BackgroundWorker.RunWorkerCompleted

的事件处理程序中

更新:在右侧(调用)线程上调用处理程序 - 这样您就可以安全地更新UI。

请参阅上面msdn页面上的代码片段。

答案 2 :(得分:0)

目前尚不清楚您的需求:应用程序等待(并且没有响应),或者应用程序不等待并保持响应。在后一种情况下,您可能希望禁用某些控件/可能的操作,直到列表完成加载。

一个肮脏的解决方法是进行某种自旋等待(Join超时几毫秒,返回结果是否已完成)并进行一些Application.DoEvents()次调用。

答案 3 :(得分:0)

简单的做法是让你的工作线程在完成时回调主应用程序,然后保留已完成线程的数量,并在主UI中执行以下操作:

while(runningThreads != 0)
{
    Application.DoEvents();
}

并让线程调用:

void OnThreadCompleted()
{
    runningThreads--;
}

最好使用BackgroundWorker而不是创建自己的线程,因为这样可以准备好所有回调机制。

答案 4 :(得分:0)

我们已经将背景工作者用于类似的事情并且运作良好,有两个观察结果:

  1. 不要将文本附加到带有+ =的文本框中,因为它会在几百行后显着降低速度。改为使用AppendText。

  2. 如果您向界面添加大量信息并且有睡眠时间(处理期间),则线程可能会“睡着”。我们通过每200行删除文本框中的文本来修复它(结果写入文件,所以我们没有丢失任何东西)。

答案 5 :(得分:0)

一种替代方法是在主线程上使用Invoke

void YourMethod()
{
    Thread linkListThread = new Thread(new ThreadStart(getLinkList));
    linkListThread.Start();
}

void getLinkList()
{
    List<string> linkList = new List<string>();
    // Your tasks

    // Done
    LinkListComplete(linkList);
}

void LinkListComplete(List<string> linkList)
{
    if (InvokeRequired)
    {
        Invoke(new Action<List<string>>(LinkListComplete),linkList);
        return;
    }

    foreach (String link in linkList)
    {
        txtOutput.Text += link;
    }
}