为什么在C#中,Queue将其元素中的数据置乱? [英] Why in C# is Queue scrambling the data in its elements?
问题描述
我对Queue的功能完全感到困惑.我正在尝试(但失败)写
小型多线程应用程序,用于在C#中收集和显示数据.
阅读完 Albahari的书并使用了Consumer/Producer之后
他描述的模式是,我的大部分数据都可以正常工作,除了我的数据似乎在
队列.在排队之前,我对象中的字段具有以下值
I am completely perplexed with how my Queue is function. I am attempting (and failing) to write
a small multi-threaded application to collect and display data in C#.
After reading through Albahari's book and using the Consumer/Producer
pattern he describes I got most of it to work except my data seems to get scrambled in the
queue. Before getting queued the fields in my object have the following values
timeStamp = 6
data [] = {4936,9845,24125,44861}
timeStamp = 6
data[] ={4936, 9845, 24125, 44861}
出队后,数据看起来像
timeStamp = 6
data [] = {64791,19466,47772,65405}
timeStamp = 6
data[] = {64791, 19466, 47772, 65405}
我不明白为什么出队后数据字段中的值会被更改? 我很困惑,所以我想把它扔在那里,看看是否有人可以指出我正确的方向来解决这个问题或指出我另一个方向去进行.
I don't understand why the values in the data filed are being changed after the dequeue? I am perplexed so I thought I'd throw it out there to see if anyone can point me in the right direction to fixing this or to point me in a different direction to proceed.
相关代码
用于存储数据的自定义对象
相关对象和字段. sensorData类是用于存储我的计算的单独类.
Relevant objects and Fields. The class sensorData is a seperate class use to store my calculations.
public class sensorData
{
public const int bufSize = 4;
public UInt16[] data = new UInt16[4];
public double TimeStamp = 0;
public int timeIndex = 0;
}
以下字段用于设置入队线程和出队线程之间的队列和信号.
The following fields are used to setup the queue and signals between the enqueue and dequeue threads.
EventWaitHandle wh = new AutoResetEvent(false);
Queue<sensorData> dataQ = new Queue<sensorData>();
object locker = new object();
排队方法/线程
这是我的工作线程,它计算四个正弦曲线并将结果排队处理. 我还将结果写入文件中,以便知道其计算结果.
This is my worker thread it calculates four Sine curves and queues the result for processing. I also write the results to a file so I know what it has calculated.
private void calculateAndEnqueueData(BackgroundWorker worker, DoWorkEventArgs e)
{
int j = 0;
double time = 0;
double dist;
UInt16[] intDist = new UInt16[sensorData.bufSize];
UInt16 uint16Dist;
// Frequencies of the four Sine curves
double[] myFrequency = { 1, 2, 5, 10 };
// Creates the output file.
StreamWriter sw2 = File.CreateText("c:\\tmp\\QueuedDataTest.txt");
// Main loop to calculate my Sine curves
while (!worker.CancellationPending)
{
// Calculate four Sine curves
for (int i = 0; i < collectedData.numberOfChannels; i++)
{
dist = Math.Abs(Math.Sin(2.0 * Math.PI * myFrequency[i] * time);
uint16Dist = (UInt16)dist;
intDist[i] = uint16Dist;
}
// Bundle the results and Enqueue them
sensorData dat = new sensorData();
dat.data = intDist;
dat.TimeStamp = time;
dat.timeIndex = j;
lock (locker) dataQ.Enqueue(dat);
wh.Set
// Output results to file.
sw2.Write(j.ToString() + ", ");
foreach (UInt16 dd in dat.intData)
{
sw2.Write(dd.ToString() + ", ");
}
sw2.WriteLine();
// Increments time and index.
j++;
time += 1 / collectedData.signalFrequency;
Thread.Sleep(2);
}
// Clean up
sw2.Close();
lock (locker) dataQ.Enqueue(null);
wh.Set();
sw2.Close();
}
输出文件 QueuedDataTest.txt
6,4936,9845,24125,44861,
6, 4936, 9845, 24125, 44861,
出队数据方法
此方法使队列中的元素出队并将其写入文件.直到在队列上找到一个null元素为止.
This Method dequeues elements from the queue and writes them to a file. Until a null element is found on the queue at which point the job is done.
private void dequeueDataMethod()
{
StreamWriter sw = File.CreateText("C:\\tmp\\DequeueDataTest.txt");
while (true)
{
sensorData data = null;
// Dequeue available element if any are there.
lock (locker)
if (dataQ.Count > 0)
{
data = dataQ.Dequeue();
if (data == null)
{
sw.Close();
return;
}
}
// Check to see if an element was dequeued. If it was write it to file.
if (data != null)
{
sw.Write(data.timeIndex.ToString() + ", ");
foreach (UInt16 dd in data.data)
sw.Write(dd.ToString() + ", ");
sw.WriteLine();
}
else
{
wh.WaitOne();
}
}
使数据出队并将其写入 DequeueDataTest.txt
Output result after dequeueing the data and writing it to DequeueDataTest.txt
6,64791,19466,47772,65405,
6, 64791, 19466, 47772, 65405,
更新1:
当前代码中的锁位置.
我已经编辑了代码,以在将数据写入文件的位置放置锁.因此,我锁定的代码块如下.
I have edited the code to place locks around the writing data to the file. So the code blocks I have locks around are as follows.
在 CalculateAndEnqueueData()方法中,我有
lock (locker) dataQ.Enqueue(dat);
wh.Set
lock(locker)
{
sw2.Write(j.ToString() + ", ");
foreach (UInt16 dd in dat.intData)
{
sw2.Write(dd.ToString() + ", ");
}
sw2.WriteLine();
}
在 dequeueDataMethod()中,我有两个带锁的区域,第一个位于此处
In the dequeueDataMethod() I have two areas with locks the first is here
lock(locker)
if (dataQ.Count > 0)
{
data = dataQ.Dequeue();
if (data == null)
{
sw.Close();
return;
}
}
我假设为 if 块中的代码锁定了更衣室.第二个是我在此处将
which I assume locks locker for the code in the if block. The second is where I write the to the file here
lock (locker)
{
sw.Write(data.timeIndex.ToString() + ", ");
foreach (UInt16 dd in data.intData)
sw.Write(dd.ToString() + ", ");
sw.WriteLine();
if (icnt > 10)
{
sw.Close();
return;
}
this.label1.Text = dataQ.Count.ToString();
}
仅此而已.
推荐答案
是因为您要一遍又一遍地写入同一数组UInt16[] intDist
吗?您不应该为每个sensorData
对象使用单独的数组吗? (顺便说一句,示例代码中sensorData.intData
应该是sensorData.data
吗?)
Is it because you are writing to the same array UInt16[] intDist
over and over again? Shouldn't you be using separate arrays for each sensorData
object? (Btw, is sensorData.intData
suppose to be sensorData.data
in your sample code?)
澄清:
在calculateAndEnqueueData()
中仅创建一个intDist
数组,因此不同的sensorData
实例都共享同一数组---如果添加+写入和删除+写入是在锁定步骤中进行的,则可以;否则,某些数据点可能会丢失/重复.
Only one intDist
array is created in calculateAndEnqueueData()
, so different sensorData
instances are all sharing the same array --- this is ok if the adding+writing and removal+writing occur in lock-step; otherwise, some data points may be missing/repeated.
建议:
直接在calculateAndEnqueueData()
中填充sensorData
实例,而不使用intDist
数组:
Populate sensorData
instances directly, without using the intDist
array, in calculateAndEnqueueData()
:
// create new sensorData instance
sensorData dat = new sensorData();
dat.TimeStamp = time;
dat.timeIndex = j;
// Calculate four Sine curves
for (int i = 0; i < collectedData.numberOfChannels; i++)
{
dat.data[i] = (UInt16) Math.Abs(Math.Sin(2.0 * Math.PI * myFrequency[i] * time);
}
// enqueue
lock (locker) dataQ.Enqueue(dat);
这篇关于为什么在C#中,Queue将其元素中的数据置乱?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!