gpt4 book ai didi

c# - 多线程进程中静态 Queue.Enqueue 期间意外数据丢失

转载 作者:行者123 更新时间:2023-12-03 03:53:45 30 4
gpt4 key购买 nike

private Queue<FrameObjectElement> _queueObject = new
Queue<FrameObjectElement>();

private static Queue<FrameObjectElement> _queueItem = new
Queue<FrameObjectElement>();

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 个相机标签,这就是它在这里的作用的意义。然后框架对象被排入_queueObject中。接下来我会有一个条件if(allowThreadEntry == PermitEntryCount)。因此,这里所做的是每次访问此函数时,allowThreadEntry 都会递增,而 permitCountEntry 保持不变。然后此函数将继续并将 _queueObject 中的第一个元素排入 _queueItem 中,一旦满足 _queueItem 的所需计数,它将引发一个向另一个类发出信号。此类将通过引发 Camera 类之前订阅的信号来进行响应,如下所示 MainForm.OnReceiveMultipleFrameEvent += new MainForm.ReceiveMultipleFrameEvent(MainForm_OnReceiveMultipleFrameEvent)

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

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

=============================  Count : 1760 ===============================
Queue item count: 0 : isClear : True
Thread ID: 17 - 3 queue in QueueObject : Camera ID : 3 : Camera Tag :
3372 : Queue item count : 1
Thread ID: 24 - 6 queue in QueueObject : Camera ID :10 : Camera Tag :
4367 : Queue item count : 2
Thread ID: 23 - 5 queue in QueueObject : Camera ID : 9 : Camera Tag :
4415 : Queue item count : 3
Thread ID: 19 - 1 queue in QueueObject : Camera ID : 5 : Camera Tag :
4108 : Queue item count : 4
Thread ID: 20 - 5 queue in QueueObject : Camera ID : 6 : Camera Tag :
3768 : Queue item count : 5
Thread ID: 14 - 1 queue in QueueObject : Camera ID : 0 : Camera Tag :
2837 : Queue item count : 6
Thread ID: 21 - 1 queue in QueueObject : Camera ID : 7 : Camera Tag :
3246 : Queue item count : 7
Thread ID: 16 - 1 queue in QueueObject : Camera ID : 2 : Camera Tag :
3552 : Queue item count : 8
Thread ID: 18 - 6 queue in QueueObject : Camera ID : 4 : Camera Tag :
3117 : Queue item count : 9
Thread ID: 15 - 3 queue in QueueObject : Camera ID :1 : Camera Tag :
2315 : Queue item count : 10
Thread ID: 22 - 4 queue in QueueObject : Camera ID :8 : Camera Tag :
4853 : Queue item count : 11
Current Camera ID: 8 : Camera ID : 3 : Camera Tag : 3372 :
Current Camera ID: 8 : Camera ID :10 : Camera Tag : 4367 :
Current Camera ID: 8 : Camera ID : 9 : Camera Tag : 4415 :
Current Camera ID: 8 : Camera ID : 5 : Camera Tag : 4108 :
Current Camera ID: 8 : Camera ID : 6 : Camera Tag : 3768 :
Current Camera ID: 8 : Camera ID : 0 : Camera Tag : 2837 :
Current Camera ID: 8 : Camera ID : 7 : Camera Tag : 3246 :
Current Camera ID: 8 : Camera ID : 2 : Camera Tag : 3552 :
Current Camera ID: 8 : Camera ID : 4 : Camera Tag : 3117 :
Current Camera ID: 8 : Camera ID : 1 : Camera Tag : 2315 :
Current Camera ID: 8 : Camera ID : 8 : Camera Tag : 4853 :
============================= Count : 1761 ===============================
Queue item count: 0 : isClear : True
Thread ID: 14 - 1 queue in QueueObject : Camera ID : 0 : Camera Tag :
2838 : Queue item count : 1
Thread ID: 16 - 1 queue in QueueObject : Camera ID : 2 : Camera Tag :
3553 : Queue item count : 2
Thread ID: 21 - 1 queue in QueueObject : Camera ID : 7 : Camera Tag :
3247 : Queue item count : 3
Thread ID: 24 - 1 queue in QueueObject : Camera ID :10 : Camera Tag :
4374 : Queue item count : 4
Thread ID: 23 - 6 queue in QueueObject : Camera ID : 9 : Camera Tag :
4416 : Queue item count : 5
Thread ID: 17 - 4 queue in QueueObject : Camera ID : 3 : Camera Tag :
3373 : Queue item count : 7
Thread ID: 15 - 3 queue in QueueObject : Camera ID : 1 : Camera Tag :
2316 : Queue item count : 7
Thread ID: 18 - 6 queue in QueueObject : Camera ID : 4 : Camera Tag :
3118 : Queue item count : 8
Thread ID: 20 - 6 queue in QueueObject : Camera ID : 6 : Camera Tag :
3769 : Queue item count : 9
Thread ID: 22 - 4 queue in QueueObject : Camera ID :8 : Camera Tag :
4854 : Queue item count : 10

我应该在 _queueItem 中有不同的计数,因为创建的每个对象只能在该段中访问一次,从而让我知道它们的元素将被排队到 _queueItem 中。但不幸的是,不知何故,程序运行一段时间后,就会出现如上所示的情况。无论我是否在这部分应用锁定 _queueItem.Enqueue(_queueObject.Peek()); 我仍然会遇到问题。我可以知道我哪里做错了吗?

最佳答案

您说队列是静态,但您已锁定实例:

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());
}

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

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

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

另请注意,即使像 .Count 这样简单的事情也需要同步,并且最好进行双重检查(您无法在方法中尽早检查计数,然后假设仍然有东西要出列,除非您在整个持续时间内保持锁定)。您的代码重复使用 .Count - 因此请非常小心。 .Count 是暂时的:一旦你读完它,如果你放弃锁,你必须假设它已经是错误的。

关于c# - 多线程进程中静态 Queue.Enqueue 期间意外数据丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13193709/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com