我在我的应用程序中实现了用于抓取网站的线程。在废弃所有网站后,我想处理它们。
form创建queueworker(创建2个worker并处理任务)。 完成所有任务后,我想在formthread中处理它们。 在这一点上,我认识到这一点
public void WaitForCompletion()
{
// Enqueue one null task per worker to make each exit.
StopWorkers();
//wait for the workers to finish
foreach (Thread worker in workers)
{
worker.Join();
}
}
在执行任务后,我(从队列工作者)开火:
public event EventHandler<ProgressEvent> UrlScanned;
if (UrlScanned != null)
{
UrlScanned(this, new ProgressEvent(task.Name, 1));
}
用以下方式捕获该事件:
urlscanner.UrlScanned += new EventHandler<ProgressEvent>(UrlScanningProgress);
private void UrlScanningProgress(object sender, ProgressEvent args)
{
if (pbarurlScan.InvokeRequired)
{
//don't use invoke when Thread.Join() is used! Deadlock
Invoke(new MethodInvoker(delegate() { UrlScanningProgress(sender, args);
//BeginInvoke(new MethodInvoker(delegate() { UrlScanningProgress(sender, args)};
}
else
{
pbarurlScan.Value++;
}
}
问题是formthread被阻塞,并且通过调用Invoke,整个应用程序现在处于死锁状态。
如何在没有死锁的情况下为formthread提供更新并进行更新(如果工作线程完成则会发生begininvoke)
答案 0 :(得分:2)
你为什么要加入?我会在每个线程结束时引发一个回调 - 也许会减少一个计数器。当计数器变为0时,然后回调UI线程并执行“全部完成”代码;类似的东西:
using System.Windows.Forms;
using System.Threading;
using System;
class MyForm : Form
{
public MyForm()
{
Button btn = new Button();
Controls.Add(btn);
btn.Text = "Go";
btn.Click += btn_Click;
}
int counter;
void btn_Click(object sender, System.EventArgs e)
{
for (int i = 0; i < 5; i++)
{
Interlocked.Increment(ref counter);
ThreadPool.QueueUserWorkItem(DoWork, i);
}
}
void DoWork(object state)
{
for (int i = 0; i < 10; i++)
{ // send progress
BeginInvoke((Action)delegate { Text += state.ToString(); });
Thread.Sleep(500);
}
EndThread(); // this thread done
}
void EndThread()
{
if (Interlocked.Decrement(ref counter) == 0)
{
AllDone();
}
}
void AllDone()
{
Invoke((Action)delegate { this.Text += " all done!"; });
}
[STAThread]
static void Main()
{
Application.Run(new MyForm());
}
}
答案 1 :(得分:0)
当所有任务完成后,我现在发起一个单独的事件。我将处理任务的逻辑移到了一个单独的函数,该函数将在接收AllUrlsScanned事件时被调用。