我完全不知道我的队列是如何运作的.我正在尝试(并且失败)编写一个小型多线程应用程序来收集和显示C#中的数据.
在阅读了Albahari的书并使用消费者/生产者模式后,他描述了我的大部分工作都可以工作,除了我的数据似乎在队列中被扰乱.在排队之前,对象中的字段具有以下值
timeStamp = 6
data [] = {4936,9845,24125,44861}
在出列数据后,数据看起来像
timeStamp = 6
data [] = {64791,19466,47772,65405}
我不明白为什么数据字段中的值在出列后会被更改?我很困惑,所以我想我会把它扔出去,看看是否有人可以指出我正确的方向来解决这个问题,或者指出我朝着不同的方向前进.
相关守则
自定义对象用于数据存储
相关对象和字段.类sensorData是用于存储我的计算的单独类.
public class sensorData { public const int bufSize = 4; public UInt16[] data = new UInt16[4]; public double TimeStamp = 0; public int timeIndex = 0; }
以下字段用于设置队列并在enqueue和dequeue线程之间发出信号.
EventWaitHandle wh = new AutoResetEvent(false); QueuedataQ = new Queue (); object locker = new object();
入队方法/线程
这是我的工作线程,它计算四条正弦曲线并将结果排队等待处理.我还将结果写入文件,因此我知道它的计算结果.
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,
出列数据方法
此方法将队列中的元素出列,并将它们写入文件.直到在队列上找到null元素,此时作业完成.
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后的输出结果
6,64791,19466,47772,65405,
更新1:
当前代码中锁的位置.
我编辑了代码,将写入数据的锁定放在文件中.所以我有锁的代码块如下.
在我的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()中,我有两个带锁的区域,第一个在这里
lock(locker) if (dataQ.Count > 0) { data = dataQ.Dequeue(); if (data == null) { sw.Close(); return; } }
我假设在if块中的代码锁定了锁定器.第二个是我在这里写文件的地方
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(); }
这就是全部.
Mitch Wheat.. 9
问题是由于您正在写入的StreamWriter上没有同步.订单不是顺序的.
问题是由于您正在写入的StreamWriter上没有同步.订单不是顺序的.