private Queue _queueObject = new 队列();
private static Queue _queueItem = new 队列();
private static int permitEntryCount = 0;
private 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个摄像机标签,因此它的作用在这里。然后将frameobject排入' _queueObject'。接下来我会有一个条件' if(allowThreadEntry == permitEntryCount)'。所以这里所做的就是每次访问此功能时,' allowThreadEntry'将在' permitCountEntry'保持不变。然后这个函数将继续并将' _queueObject'中的第一个元素排入队列。 to' _queueItem'并且一旦满足所需的_queueItem计数,它就会向另一个类别发出信号。这个类将通过提出一个Camera类早先已经显示的信号来响应,如图所示' MainForm.OnReceiveMultipleFrameEvent + = new MainForm.ReceiveMultipleFrameEvent(MainForm_OnReceiveMultipleFrameEvent)'。
空隙 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:QueueObject中的19 - 1队列:摄像机ID:5:摄像机标记: 4108:队列项目数:4
线程ID:队列对象中的20 - 5队列:摄像机ID:6:摄像机标记: 3768:队列项目数:5
线程ID:队列对象中的14 - 1队列:摄像机ID:0:摄像机标记: 2837:队列项目数:6
线程ID:21 - QueueObject中的队列:摄像机ID:7:摄像机标签: 3246:队列项目数:7
线程ID:QueueObject中的16 - 1队列:摄像机ID:2:摄像机标记: 3552:队列项目数:8
线程ID:队列对象中的18 - 6队列:摄像机ID:4:摄像机标记: 3117:队列项目数:9
线程ID:QueueObject中的15 - 3队列:摄像机ID:1:摄像机标记: 2315:队列项目数:10
线程ID:22 - QueueObject中的队列:摄像机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 - 1队列:摄像机ID:0:摄像机标记: 2838:队列项目数:1
线程ID:QueueObject中的16 - 1队列:摄像机ID:2:摄像机标记: 3553:队列项目数:2
线程ID:21 - QueueObject中的队列:摄像机ID:7:摄像机标签: 3247:队列项目数:3
线程ID:QueueObject中的24 - 1队列:摄像机ID:10:摄像机标记: 4374:队列项目数:4
线程ID:QueueObject中的23 - 6队列:摄像机ID:9:摄像机标记: 4416:队列项目数:5
线程ID:队列对象中的17 - 4队列:摄像机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:22 - QueueObject中的队列:摄像机ID:8:摄像机标记: 4854:队列项目数:10
我应该在' _queueItem'中有不同的计数。因为创建的每个对象只能在该段中访问一次,因此让我知道它们的元素将被排入' _queueItem'。但遗憾的是,在程序运行一段时间之后,会出现如上所示的情况。要么我在这部分上应用锁定' _queueItem.Enqueue(_queueObject.Peek());'我仍然会遇到问题。我可以知道我哪里做错了吗?
答案 0 :(得分:3)
您说队列为static
,但您已锁定实例:
lock (this)
{
_queueItem.Enqueue(_queueObject.Peek());
}
如果您有多个实例,则表示每个实例都单独锁定 。更好的方法是拥有一个专用的静态锁定对象,然后锁定它。你或许可以作弊:
lock (_queueItem)
{
_queueItem.Enqueue(_queueObject.Peek());
}
如果永远不会重新分配_queueItem
,但最安全的方法是:
static readonly object lockObj = new object();
lock (lockObj)
{
_queueItem.Enqueue(_queueObject.Peek());
}
请注意所有对 的队列的访问权限必须,并且所有必须使用相同的锁定对象。
如果您分别与两个队列对话,可能会减少一些争用,但在这种情况下尽量避免使用嵌套锁,因为如果做得不好会导致死锁;例如,要从实例队列中查看并排入 static 队列,您可以使用:
object item;
lock(instanceLock) {
item = _queueObject.Peek();
}
lock(staticLock) {
_queueItem.Enqueue(item);
}
另请注意,即使像.Count
这样简单的事情也需要同步,并且理想情况下需要进行双重检查(您无法在方法中检查早期计数,然后再进行检查假设仍有东西出队,除非你在整个持续时间内保持锁定。您的代码重复使用.Count
- 因此请非常小心。 .Count
是暂时的:只要你阅读它,如果放弃锁定,就必须认为它已经错了。
答案 1 :(得分:2)
使用this
锁定是邪恶的。检查几个参考文献:
http://haacked.com/archive/2005/04/12/neverlockthis.aspx
始终使用像:
这样的专用对象private static object _queueLock = new object();
答案 2 :(得分:2)
为什么不让Queue
处理锁定?使用内部同步的ConcurrentQueue<T>
。
答案 3 :(得分:1)
请勿使用锁定(此) - 请参阅here。如果要在类的多个实例之间共享队列,则需要锁定由所有实例共享的静态对象。目前,每个类实例都有自己的锁,因此它将忽略其他实例应用的任何锁。