4

プライベート キュー _queueObject = new Queue();

プライベート静的キュー _queueItem = new Queue();

private static int permitEntryCount = 0;

プライベート int allowThreadEntry = 0;

上記のように、2 つのキュー変数があります。

public Camera(IVideoSource source, MotionDetector detector)
{
   VideoSource = source; 
   _motionDetector = detector;
   VideoSource.NewFrame += VideoNewFrame; 
   MainForm.OnRegisterClickedEvent += new MainForm.RegisterClickedEventHandler(MainForm_OnRegisterClickedEvent);
   MainForm.OnReceiveMultipleFrameEvent += new MainForm.ReceiveMultipleFrameEventHandler(MainForm_OnReceiveMultipleFrameEvent);
}

Camera クラスがあり、上記はコンストラクター実装の一部です。イベント VideoNewFrame を常にリッスンしているビデオ ソース。以下に示すコードは、VideoNewFrame のコードの一部です。

FrameObjectElement frameObj = new FrameObjectElement();
frameObj.cameraID = CW.Camobject.id;
frameObj.cameraTag = _FPGAFrameCount / 2;
frameObj.FirstFrameBuffer = BitmapToRgbValues(twoframe_arg.GetFirstBitmap(352, 288));
frameObj.SecondFrameBuffer = BitmapToRgbValues(twoframe_arg.GetSecondBitmap(352, 288));

if (_queueObject.Count > 5)
    _queueObject.Clear();

_queueObject.Enqueue(frameObj);

if (allowThreadEntry == permitEntryCount && isClear) 
{
    if (_queueObject.Count !=  0)
    {
        lock (this)
        {
            _queueItem.Enqueue(_queueObject.Peek());
        }
        Debug.WriteLine("Thread ID: " + Thread.CurrentThread.ManagedThreadId.ToString() +
        " - " + _queueObject.Count.ToString() +
        " queue in QueueObject : Camera ID : " + _queueObject.Peek().cameraID.ToString() +
        " : Camera Tag : " + _queueObject.Peek().cameraTag.ToString() + 
        " : Queue item count : " + _queueItem.Count.ToString());

        _queueObject.Dequeue();

        if (_queueItem.Count == numberOfCamera && isAllow)
        {
            CurrentID = CW.Camobject.id;
            isAllow = false;
        }

        allowThreadEntry++;
        if (_queueItem.Count == numberOfCamera)
        {
            if (CurrentID == CW.Camobject.id)
            {
                isClear = false;
                //allowEntry = false;

                //Debug.WriteLine("-- Count: " + allowThreadEntry.ToString() + " --");

                foreach (FrameObjectElement foE in _queueItem)
                {
                    Debug.WriteLine("Current Camera ID: " + CW.Camobject.id +
                        " : Camera ID : " + foE.cameraID.ToString() +
                        " : Camera Tag : " + foE.cameraTag.ToString() + " :");
                }

                MultipleFrameEventArgs newMul = new MultipleFrameEventArgs();
                newMul.itemObj = _queueItem;

                if (OnMultupleFrameEvent != null)
                    OnMultupleFrameEvent(newMul);

                _queueItem.Clear();
                isAllow = true;
                isClear = true;
                Debug.WriteLine("Queue item count: " + _queueItem.Count.ToString() +
                    " : isClear : " + isClear.ToString());
            }
        }   
    }
}

基本的に、ここで達成しようとしているのは、フレーム ID、タグ、その最初と 2 番目のフレームを収集し、オブジェクト (struct FrameObjectElement) に格納することです。2 つのフレームのすべてのコレクションは 1 つのカメラ タグを表すため、ここでの役割の意味は次のとおりです。次に、frameobject が「_queueObject」のキューに入れられます。次に、「if(allowThreadEntry == permitEntryCount)」という条件があります。したがって、ここで行われているのは、この関数がアクセスされるたびに、「allowThreadEntry」が増加し、「permitCountEntry」は同じままです。次に、この関数は、'_queueObject' の最初の要素を '_queueItem' にエンキューし、_queueItem の必要な数が満たされると、別のクラスにシグナルを発生させます。

void MainForm_OnReceiveMultipleFrameEvent(MainForm.ReceiveMultpleFrameEventArgs e) { permitEntryCount++; }

シグナルを受信すると、permitEntryCount がインクリメントされ、関数に再びアクセスできるようになります。これを行う理由は、このクラスが作成されるのは、私が持っているオブジェクト カメラの数に依存するためです。11 台のカメラがある場合、このクラスを処理する 11 個の workerThread が実行されます。フレームを非静的キューに入れ、最初の要素を静的キューに集めて、他のプロセスに渡します。ここで直面している問題は次のとおりです。

============================= カウント: 1760 ================== =============

キュー アイテム数: 0 : isClear : True

スレッド ID: 17 - QueueObject の 3 キュー: カメラ ID: 3: カメラ タグ: 3372: キュー アイテム数: 1

スレッド ID: 24 - 6 QueueObject のキュー: カメラ ID:10: カメラ タグ: 4367: キュー アイテム数: 2

スレッド ID: 23 - 5 QueueObject のキュー: カメラ ID: 9: カメラ タグ: 4415: キュー アイテム数: 3

スレッド ID: 19 - QueueObject の 1 つのキュー: カメラ ID: 5: カメラ タグ: 4108: キュー アイテム数: 4

スレッド ID: 20 - 5 QueueObject のキュー: カメラ ID: 6: カメラ タグ: 3768: キュー アイテム数: 5

スレッド ID: 14 - QueueObject の 1 キュー: カメラ ID: 0: カメラ タグ: 2837: キュー アイテム数: 6

スレッド ID: 21 - QueueObject の 1 キュー: カメラ ID: 7: カメラ タグ: 3246: キュー アイテム数: 7

スレッド ID: 16 - QueueObject の 1 キュー: カメラ ID: 2: カメラ タグ: 3552: キュー アイテム数: 8

スレッド ID: 18 - 6 QueueObject のキュー: カメラ ID: 4: カメラ タグ: 3117: キュー アイテム数: 9

スレッド ID: 15 - 3 QueueObject のキュー: カメラ ID:1: カメラ タグ: 2315: キュー アイテム数: 10

スレッド ID: 22 - QueueObject の 4 キュー: カメラ ID:8: カメラ タグ: 4853: キュー アイテム数: 11

現在のカメラ ID: 8 : カメラ ID : 3 : カメラ タグ : 3372 :

現在のカメラ ID: 8 : カメラ ID :10 : カメラ タグ : 4367 :

現在のカメラ ID: 8 : カメラ ID : 9 : カメラ タグ : 4415 :

現在のカメラ ID: 8 : カメラ ID : 5 : カメラ タグ : 4108 :

現在のカメラ ID: 8 : カメラ ID : 6 : カメラ タグ : 3768 :

現在のカメラ ID: 8 : カメラ ID : 0 : カメラ タグ : 2837 :

現在のカメラ ID: 8 : カメラ ID : 7 : カメラ タグ : 3246 :

現在のカメラ ID: 8 : カメラ ID : 2 : カメラ タグ : 3552 :

現在のカメラ ID: 8 : カメラ ID : 4 : カメラ タグ : 3117 :

現在のカメラ ID: 8: カメラ ID: 1: カメラタグ: 2315:

現在のカメラ ID: 8 : カメラ ID : 8 : カメラ タグ : 4853 :

============================= カウント: 1761 ================== =============

キュー アイテム数: 0 : isClear : True

スレッド ID: 14 - QueueObject の 1 キュー: カメラ ID: 0: カメラ タグ: 2838: キュー アイテム数: 1

スレッド ID: 16 - QueueObject の 1 キュー: カメラ ID: 2: カメラ タグ: 3553: キュー アイテム数: 2

スレッド ID: 21 - QueueObject の 1 キュー: カメラ ID: 7: カメラ タグ: 3247: キュー アイテム数: 3

スレッド ID: 24 - QueueObject の 1 つのキュー: カメラ ID:10: カメラ タグ: 4374: キュー アイテム数: 4

スレッド ID: 23 - 6 QueueObject のキュー: カメラ ID: 9: カメラ タグ: 4416: キュー アイテム数: 5

スレッド ID: 17 - QueueObject の 4 キュー: カメラ ID: 3: カメラ タグ: 3373: キュー アイテム数: 7

スレッド ID: 15 - 3 QueueObject のキュー: カメラ ID: 1: カメラ タグ: 2316: キュー アイテム数: 7

スレッド ID: 18 - 6 QueueObject のキュー: カメラ ID: 4: カメラ タグ: 3118: キュー アイテム数: 8

スレッド ID: 20 - 6 QueueObject のキュー: カメラ ID: 6: カメラ タグ: 3769: キュー アイテム数: 9

スレッド ID: 22 - QueueObject の 4 キュー: Camera ID:8: Camera Tag: 4854: Queue item count: 10

作成されたすべてのオブジェクトはこのセグメントで 1 回しかアクセスできないため、「_queueItem」には異なるカウント数が必要です。これにより、それらの要素が「_queueItem」にエンキューされることがわかります。しかし残念なことに、しばらくプログラムを実行すると、上記のような現象が発生します。この部分にロックを適用するかどうかのどちらか '_queueItem.Enqueue(_queueObject.Peek());' 私はまだ問題を抱えています。私がどこで間違ったのか分かりますか?

4

4 に答える 4

3

あなたはキューが であると言いますが、あなたはインスタンスstaticに対してロックしています:

lock (this)
{
    _queueItem.Enqueue(_queueObject.Peek());
}

複数のインスタンスがある場合、それはそれぞれが独立してロックしていることを意味します。より良いアプローチは、専用の静的ロック オブジェクトを用意し、それに対してロックすることです。あなたはカンニングできるかもしれません:

lock (_queueItem)
{
    _queueItem.Enqueue(_queueObject.Peek());
}

if_queueItemが再割り当てされることはありませんが、最も安全な方法は次のとおりです。

static readonly object lockObj = new object();
lock (lockObj)
{
    _queueItem.Enqueue(_queueObject.Peek());
}

キューへのすべてのアクセスは同期する必要があり、すべて同じロック オブジェクトを使用する必要があることに注意してください。

2 つのキューを別々に扱うと競合を少し減らすことができるかもしれませんが、このシナリオではネストされたロックを使用しないようにしてください。たとえば、インスタンスキューからピークして静的キューにエンキューするには、次のように使用できます。

object item;
lock(instanceLock) {
    item = _queueObject.Peek();
}
lock(staticLock) {
    _queueItem.Enqueue(item);
}

.Countまた、同期する必要があるような単純なものでさえ、理想的には再確認する必要があることに注意してください(メソッドの早い段階でカウントを確認し、その後、ロックを維持しない限り、まだデキューするものがあると仮定してカウントを確認することはできません)。全期間)。あなたのコードは を繰り返し使用するため、十分注意して.Countください。は一時的なものです。読んだ直後にロックを放棄した場合、それはすでに間違っていると想定する必要があります。.Count

于 2012-11-02T10:49:18.540 に答える
2

Queueハンドルをロックさせてみませんか?ConcurrentQueue<T>内部で同期する を使用します。

于 2012-11-02T11:00:36.347 に答える
2

使用してロックすることthisは悪です。いくつかの参照を確認してください。

lock(this) {…} が悪いのはなぜですか?

http://haacked.com/archive/2005/04/12/neverlockthis.aspx

次のような専用オブジェクトを常に使用します。

private static object _queueLock = new object();
于 2012-11-02T10:53:42.787 に答える
1

lock(this) を使用しないでください -こちらを参照してください。クラスの複数のインスタンス間でキューを共有している場合は、すべてのインスタンスで共有される静的オブジェクトをロックする必要があります。現在、各クラス インスタンスには独自のロックがあるため、他のインスタンスによって適用されたロックは無視されます。

于 2012-11-02T10:54:07.980 に答える