0

スレッドプール内のすべてのスレッドがいつタスクを終了したかを確認する方法を探しています。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 の量は常に合計数よりも 1 少なくなります。これは、最後のスレッドが 'Reporting back' などではないようなものです。誰にもアイデアはありますか?

ありがとうございました

4

2 に答える 2

3

上記のコードにはいくつかの問題があります。

  1. 例外処理を含めていますが、への呼び出しがInterlocked.Decrementfinally ブロックにありません。これは、例外によって がjobCounter適切に削減されないことを意味します。
  2. すべてのスレッドで、メソッド内でロックしています。これにより、これらの ThreadPool スレッドはすべて同じ変数 ( ) をロックしているため、事実上、これらの ThreadPool スレッドの 1 つだけが任意の時点で実行できるようになります_threadLock。これが必要な場合、複数のスレッド プール スレッドを使用する理由はありません。ループ内のすべてのアイテムを 1 つのスレッドで処理するだけです。
  3. スレッド プール スレッドから UI 要素に直接アクセスしているように見えます (ただし、コードは 100% 明確ではありません) (例: chkTwitt.Checked)。これは信頼できません。
  4. resultすべてのスレッドで共有される単一の変数にすべてが設定されています。実際の意味で、これがどのように使用されるかは明確ではありません。

アイテム (URL) のコレクションを効果的に処理しているだけなので、アイテムを処理するParallel.ForEachために for evenPLINQを使用することも検討する必要があります。

于 2012-07-06T16:00:46.470 に答える
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に結果が複数回表示されるという問題も解決しました。

また、ロックを解除することもでき(そもそも意味がありませんでした)、この経験を通じてマルチスレッドについてもう少し学びました:)

于 2012-07-10T08:06:45.193 に答える