我们有一个ConcurrentQueue,用于在3个线程之间共享数据。线程 A 不断用数据填充队列。线程 B 旨在将此数据记录到文件中。线程 C 应该检索队列中最年轻的条目(或尽可能接近最年轻的条目),对其执行一些操作并在屏幕上显示结果。
线程 B 为了及时对文件写入操作进行集群,执行以下操作:
if (cq.Count > 100)
{
while (cq.Count > 1)
{
qElement = PopFromCq(cq); // PopFromCq uses cq.TryDequeue()
bw.Write(qElement.data); // bw is a binary writer
}
}
else
{
System.Threading.Thread.Sleep(10);
}
即,它等待至少 100 个元素排队,然后将它们写入磁盘。不过,它始终在队列中维护至少一个项目,原因是我们希望线程 C 始终可以访问至少一个项目。
线程 C 中的循环如下所示:
while (threadsRunning)
{
System.Threading.Thread.Sleep(500); // Update twice per second
ProcessDataAndUpdateScreen(cq.ElementAt(cq.Count - 1)); // our terrible attempt at looking at the latest (or close to latest) entry in the queue
}
在此循环中,由于将数据写入磁盘的线程与 cq 之间的争用,我们有时会收到异常。ElementAt(cq.计数-1)呼叫。我相信正在发生的事情如下:
- 重庆。计数的计算方法是,比如说 90。
- 到那时,线程 B 已经开始循环,它正在将数据从队列中取消排队以写入磁盘
- 到cq的时候。调用 ElementAt(),线程 B 消耗了许多项目,例如 (cq.计数 - 1) 不再指向队列中的有效条目。
上存在多个线程的情况下访问队列中最年轻的条目的好方法的任何想法?
问候
A-B 通信和 A-C 通信是否都必须通过队列? 如果你让线程 A 将每个条目写入队列(供 B 读取和记录),并将它刚刚排队的条目保存在某处的易失性属性中,该怎么办? 每当 C 想要获取最年轻的元素时,它都可以直接从该属性中读取。
编辑:而不是仅仅依赖易失性属性,你实际上应该使用Interlocked.CompareExchange<T>(T, T)
来设置和读取"最年轻的条目"属性。