4

私有队列_queueObject = new Queue();

私有静态队列_queueItem =新队列();

私有静态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、标签、它的第一帧和第二帧,然后存储在一个对象(struct FrameObjectElement)中。每个 2 帧的集合将代表 1 个相机标签,因此在这里它的作用的含义。然后框架对象在“_queueObject”中排队。接下来我会有一个条件'if(allowThreadEntry == permitEntryCount)'。所以这里所做的是每次访问这个函数时,'allowThreadEntry' 将增加,而'permitCountEntry' 保持不变。然后此函数将继续并将“_queueObject”中的第一个元素排入“_queueItem”队列,一旦满足所需的_queueItem 计数,它将向另一个类发出信号。

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

收到信号后, permitEntryCount 将递增,从而允许再次访问该函数。为什么我这样做是因为创建这个类取决于我有多少物体相机。如果我有 11 个摄像头,我将有 11 个 workerThread 运行处理这个类。我将它们的帧排列在一个非静态队列中,并将它们的第一个元素收集到一个静态队列中,该队列将传递给我的其他进程。我在这里面临的问题如下:

============================== 计数:1760 ================== ==============

队列项目计数:0:isClear:True

线程 ID:QueueObject 中的 17 - 3 个队列:相机 ID:3:相机标签:3372:队列项目数:1

线程 ID:QueueObject 中的 24 - 6 个队列:相机 ID:10:相机标签:4367:队列项目数:2

线程 ID:QueueObject 中的 23-5 个队列:相机 ID:9:相机标签:4415:队列项目数:3

线程 ID:19 - QueueObject 中的 1 个队列:相机 ID:5:相机标签:4108:队列项目数:4

线程 ID:QueueObject 中的 20-5 个队列:相机 ID:6:相机标签:3768:队列项目数:5

线程 ID:QueueObject 中的 14-1 个队列:相机 ID:0:相机标签:2837:队列项目数:6

线程 ID:QueueObject 中的 21-1 个队列:相机 ID:7:相机标签:3246:队列项目数:7

线程 ID:16 - QueueObject 中的 1 个队列:相机 ID:2:相机标签:3552:队列项目数:8

线程 ID:QueueObject 中的 18 - 6 个队列:相机 ID:4:相机标签:3117:队列项目数:9

线程 ID:QueueObject 中的 15 - 3 个队列:相机 ID:1:相机标签:2315:队列项目数:10

线程 ID:QueueObject 中的 22-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:QueueObject 中的 14-1 个队列:相机 ID:0:相机标签:2838:队列项目数:1

线程 ID:16-1 队列对象中的队列:相机 ID:2:相机标签:3553:队列项目计数:2

线程 ID:QueueObject 中的 21-1 个队列:相机 ID:7:相机标签:3247:队列项目数:3

线程 ID:24 - QueueObject 中的 1 个队列:相机 ID:10:相机标签:4374:队列项目数:4

线程 ID:23 - 6 QueueObject 中的队列:相机 ID:9:相机标签:4416:队列项目数:5

线程 ID:17 - 4 QueueObject 中的队列:相机 ID:3:相机标签:3373:队列项目数:7

线程 ID:QueueObject 中的 15-3 个队列:相机 ID:1:相机标签:2316:队列项目数:7

线程 ID:18 - 6 队列对象中的队列:相机 ID:4:相机标签:3118:队列项目数:8

线程 ID:QueueObject 中的 20-6 个队列:相机 ID:6:相机标签:3769:队列项目数:9

线程 ID:QueueObject 中的 22-4 队列:相机 ID:8:相机标签:4854:队列项目数:10

我应该在“_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());
}

请注意,对队列的所有访问都必须同步,并且必须使用相同的锁定对象。

如果您分别与两个队列通信,您可能能够减少一些争用,但请尽量避免在这种情况下使用嵌套锁,因为如果做得不好会导致死锁;例如,要从实例队列中窥视并进入静态队列,您可以使用:

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

还要注意,即使是简单的事情也.Count需要同步,最好是仔细检查(你不能在方法的早期检查计数,然后假设还有一些东西要出队,除非你为此保持锁定整个持续时间)。您的代码重复使用.Count- 所以请非常小心。.Count是暂时的:一旦你读了它,如果你放弃了锁,你必须假设它已经错了。

于 2012-11-02T10:49:18.540 回答
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 回答
2

你为什么不让Queue把手锁定?使用ConcurrentQueue<T>内部同步的 a 。

于 2012-11-02T11:00:36.347 回答
1

不要使用 lock(this) - 请参见此处。如果您在类的多个实例之间共享队列,则需要锁定由所有实例共享的静态对象。目前每个类实例都有自己的锁,因此它将忽略其他实例应用的任何锁。

于 2012-11-02T10:54:07.980 回答