我正在寻找一种检查线程池中所有线程何时完成任务的方法。目前我正在使用一个计数器,当一个线程完成它的工作时以及counter == 0
我正在调用我的WorkComplete
方法时递减。这似乎有效,但当我到达最后的“工作”时,似乎没有处理结果?或者至少UI没有得到它。这是我目前拥有的:
排队工作项目+递增计数器
foreach (string s in URLs)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), s);
Interlocked.Increment(ref counter);
}
做好工作:
public void DoWork(object sender)
{
lock (_threadLock)
{
try
{
string url = (string)sender;
result.URL = url;
if (chkFb.Checked)
{
result.Shares = grabber.GetFacebookShares(url);
}
if (chkTwitt.Checked)
{
result.Tweets = grabber.GetTweetCount(url);
}
if (chkPlusOne.Checked)
{
result.PlusOnes = grabber.GetPlusOnes(url);
}
Interlocked.Decrement(ref counter);
this.Invoke(new ThreadDone(ReportProgress), result);
}
catch (Exception exc)
{
MessageBox.Show(string.Format("Errror: {0}", exc.Message);
}
finally
{
if (counter == 0)
{
this.Invoke(new ThreadDone(ReportProgress), result);
this.Invoke(new Complete(WorkComplete));
}
}
}
}
但是,处理的URL总量总是比总数少一个,这几乎就像最后一个帖子不是“报告回来”或其他东西。有没有人有任何想法?
三江源
答案 0 :(得分:3)
上述代码中存在一些问题:
Interlocked.Decrement
的调用不在finally块中。这意味着异常将阻止jobCounter
正确缩减。_threadLock
)上。如果需要这样,就没有理由使用多个线程池线程 - 只需要一个线程处理循环中的所有项目,因为这实际上就是你现在正在做的事情。chkTwitt.Checked
)。这不可靠。result
变量,该变量在所有线程中共享。在实际意义上,不清楚如何使用它。鉴于您实际上只是处理一组项目(URL),您可能还需要考虑使用Parallel.ForEach
进行偶数PLINQ
处理这些项目。
答案 1 :(得分:0)
好吧,我解决了这个问题。
ScrapeResult result = new ScrapeResult();
string url = (string)sender;
result.URL = url;
if (chkFb.Checked)
{
result.Shares = grabber.GetFacebookShares(url);
}
if (chkTwitt.Checked)
{
result.Tweets = grabber.GetTweetCount(url);
}
if (chkPlusOne.Checked)
{
result.PlusOnes = grabber.GetPlusOnes(url);
}
Interlocked.Decrement(ref counter);
this.Invoke(new ThreadDone(ReportProgress), result);
我没有在result
方法中重用相同的变量DoWork
,而是为每个线程创建一个新变量,这样线程就不可能获得任何旧的/已处理的数据(因为我创建了一个每个新实例)。这也解决了我在UI上不止一次显示结果时遇到的一些问题。
我还能够移除锁定(首先没有任何意义),并通过以下经验了解了多线程:)