2

生産者/消費者パターンを使用して、一部のデータを処理および保存しようとしています。私は2つのtherad間のシグナリングにAutoResetEventを使用していますここに私が持っているコードがあります

これがプロデューサー機能です

 public Results[] Evaluate()
    {
        processingComplete = false;
        resultQueue.Clear();
        for (int i = 0; i < data.Length; ++i)
            {
                if (saveThread.ThreadState == ThreadState.Unstarted)
                    saveThread.Start();
               //-....
               //Process data 
               // 
                lock (lockobject)
                {
                    resultQueue.Enqueue(result);
                }

                signal.Set();
            }
            processingComplete = true;
        }

そしてここに消費関数があります

   private void SaveResults()
    {
        Model dataAccess = new Model();

        while (!processingComplete || resultQueue.Count > 0)
        {
            if (resultQueue.Count == 0)
                signal.WaitOne();
            ModelResults result;
            lock (lockobject)

            {
                result = resultQueue.Dequeue();
            }
            dataAccess.Save(result);
        }
        SaveCompleteSignal.Set();
    }

したがって、私の問題は、キューが空であるためにresultQueue.Dequeue()がInvalidOperation例外をスローすることです。何が間違っているのかわからないので、シグナルを送信するべきではありません。そのブロックの上のWaitOne()は、キューが空ですか?

4

3 に答える 3

2

適切なロックがないため、同期の問題が発生します。

カウントチェックを含むすべてのキューアクセスをロックする必要があります。

さらに、この方法でThread.ThreadStateを使用することは、「悪い考え」です。ThreadStateのMSDNドキュメントから:

「スレッドの状態は、デバッグシナリオでのみ重要です。コードでは、スレッドのアクティビティを同期するためにスレッドの状態を使用しないでください。」

同期を処理する手段としてこれを信頼することはできません。使用する前にスレッドが開始されるように再設計する必要があります。起動していない場合は、初期化しないでください。(いつでもnullチェックを使用できます-スレッドがnullの場合は、スレッドを作成して開始します)。

于 2009-12-10T18:27:28.803 に答える
1

同期されたコンテキストの外部でキューのカウントを確認します。キューはスレッドセーフではないため、これは問題になる可能性があり(おそらく、エンキューが1を返すカウントを処理しているが、アイテムをデキューすることはできません)、とにかく複数のコンシューマーを使用すると、深刻な問題が発生します。

ジョセフ・アルバハリが書いたスレッドの記事を読みたいと思うかもしれません。彼はあなたの問題の良いサンプルであり、 OS同期オブジェクトのない「より良い」解決策も持っています。

于 2009-12-10T18:24:15.513 に答える
0

キューへのすべての参照の周りにlock()を配置する必要があります。また、処理が完了したことを確認する際にいくつかの問題があります(キューの最後にシグナルが表示されますが、キューは空になります)。

public Results[] Evaluate()
{
    processingComplete = false;
    lock(lockobject) 
    {
        resultQueue.Clear();
    }
    for (int i = 0; i < data.Length; ++i)
    {
        if (saveThread.ThreadState == ThreadState.Unstarted)
            saveThread.Start();
       //-....
       //Process data 
       // 
        lock (lockobject)
        {
            resultQueue.Enqueue(result);
        }

        signal.Set();
    }
    processingComplete = true;
}

private void SaveResults()
{
    Model dataAccess = new Model();

    while (true)
    {
        int count;

        lock(lockobject)  
        {
            count = resultQueue.Count;
        }
        if (count == 0)
            signal.WaitOne();

        lock(lockobject)  
        {
            count = resultQueue.Count;
        }
        // we got a signal, but queue is empty, processing is complete
        if (count == 0)
            break;

        ModelResults result;
        lock (lockobject)
        {
            result = resultQueue.Dequeue();
        }
        dataAccess.Save(result);
    }
    SaveCompleteSignal.Set();
}
于 2009-12-10T19:04:01.307 に答える