c#backgroundworker被.Net任务打断了吗?

时间:2016-01-14 09:32:17

标签: c# performance backgroundworker

我有一个Backgroundworker来从UPD设备收集数据。我需要每35毫秒从设备中获取数据,否则它将被覆盖。问题是我每隔+/- 5秒就错过了一些数据。如果我查看Trace中生成的时间戳,我看到延迟在backgroundworker线程之外。 我已经通过在我需要时刷新跟踪日志和两个文本编写器对象来提高性能。

有谁知道延迟的原因是什么?

这是我的代码:

public DataCaptureTabViewModel()
{
  SelectDirectoryCommand = new RelayCommand(OnSelectDirectoryCommand);
  OpenDirectoryCommand= new RelayCommand(OnOpenDirectoryCommand);
  StartStopCaptureCommand = new RelayCommand(OnStartStopCaptureCommand);

  var cmdAppl = new GetApplicationSettings();
  Mediator.Default.Raise(cmdAppl);
  var applicationSettings = cmdAppl.AppSettings;

  FilePath = applicationSettings.DefaultPath;

  EnableControls = false;

  _backgroundWorker = new BackgroundWorker
  {
    WorkerSupportsCancellation = true,
    WorkerReportsProgress = true
  };
  _backgroundWorker.DoWork += CaptureThread_DoWork;
  _backgroundWorker.ProgressChanged += CaptureThread_ProgressChanged;
}


private void CaptureThread_DoWork(object sender, DoWorkEventArgs e)
{
  var bgw = (BackgroundWorker)sender;
  if (bgw == null) throw new ArgumentException("UpdateBackgroundWorker_DoWork: wrong arguments!");
  bgw.ReportProgress(-1, new StringEventArgs(string.Format("Horizontal: {0}/{1}   Vertical: {2}/{3} [dropped lines/total]", 0, 0, 0, 0)));

  var lastCaptureTime = DateTime.Now;
  var lastStatusUpdateTime = DateTime.Now;
  var scannedLinesW = 0;
  var scannedLinesH = 0;
  var droppedLinesW = 0;
  var droppedLinesH = 0;
  const int nrOfLinesToFlushFileAfter = 500;
  uint lastRetrievedBufferTimeStampW = 1;
  uint lastRetrievedBufferTimeStampH = 1;
  var firstTimeStampW = true;
  var firstTimeStampH = true;
  TextWriter twW = new StreamWriter(_completeFilePadW, true);
  TextWriter twH = new StreamWriter(_completeFilePadH, true);
  const string header = "Timestamp; Position;";
  var headerW = header;
  for (var i = 0; i < NrOfHorizontalBits; i++)
  {
    headerW += string.Format("b{0};", i);
  }
  var headerH = header;
  for (var i = 0; i < NrOfVerticalBits; i++)
  {
    headerH += string.Format("b{0};", i);
  }
  twW.WriteLine(headerW);
  twH.WriteLine(headerH);
  //send cmd to clear overflow counters and make all buffers invalid
  SelectedEmbeddedController.ResetBeamBuffers();
  //retrieve sampleTime
  var sampleTime = RetrieveSampleTime();
  if (sampleTime == 0) sampleTime = 1;
  var flushFilesAfterInMs = sampleTime * nrOfLinesToFlushFileAfter;
  var lastFlushedTimeW = DateTime.Now;
  var lastFlushedTimeH = lastFlushedTimeW.AddMilliseconds((int)(flushFilesAfterInMs / 3));
  var lastFlushedTraceBuffer = lastFlushedTimeW.AddMilliseconds((int)(flushFilesAfterInMs / 3) * 2);
  while (!bgw.CancellationPending)
  {
    //wait, flush in this wait time if needed
    var now = DateTime.Now;
    if (Helpers.TimeDiffInMs(now, lastFlushedTimeW) > flushFilesAfterInMs)
    {
      lastFlushedTimeW = DateTime.Now;
      twW.Flush();
    }
    if (Helpers.TimeDiffInMs(now, lastFlushedTimeH) > flushFilesAfterInMs)
    {
      lastFlushedTimeH = DateTime.Now;
      twH.Flush();
    }
    if (Helpers.TimeDiffInMs(now, lastFlushedTraceBuffer) > flushFilesAfterInMs)
    {
      lastFlushedTraceBuffer = DateTime.Now;
      Trace.Flush();
    }
    var delay = (int)(MinCaptureTimeInMs - Helpers.TimeDiffInMs(DateTime.Now, lastCaptureTime));
    if (delay > 0)
    {
      Thread.Sleep(delay);
    }
    //end wait

    // capturing data
    var startFetch = DateTime.Now;
    DebugLogging.WriteLine("*** Fetch all buffers");
    const int nrOfRegistersW = (NrOfBuffersUsed * NrOfRegistersPerBufferW);
    const int nrOfRegistersH = (NrOfBuffersUsed * NrOfRegistersPerBufferH);
    var registersImageW = RetrieveCompleteRegisterBlock(FirstScanRegisterW, nrOfRegistersW);
    var registersImageH = RetrieveCompleteRegisterBlock(FirstScanRegisterH, nrOfRegistersH);
    DebugLogging.WriteLine("*** Fetch all buffers, ready, FetchTime={0}; timeDiff={1} ms", Helpers.TimeDiffInMs(DateTime.Now, startFetch), Helpers.TimeDiffInMs(DateTime.Now, lastCaptureTime));
    lastCaptureTime = DateTime.Now;

    /* process Width data */
    if (registersImageW == null)
    {
      DebugLogging.WriteLine("Warning: Width, failed to fetch!");
    }
    else
    {
      //first store the received register data into DataStructure List
      var dataStructureListW = new List<DataStructure>();
      for (var i = 0; i < NrOfBuffersUsed; i++)
      {
        dataStructureListW.Add(RetrieveDataBuffer(registersImageW, (NrOfRegistersPerBufferW * i), NrOfHorizontalBits));
      }

      //delete zerro and older datasets
      dataStructureListW.RemoveAll(x => x.TimeStampInMs == 0 || x.TimeStampInMs <= lastRetrievedBufferTimeStampW);

      //order list by timestamp
      var sortedDataStructureListW = dataStructureListW.OrderBy(o => o.TimeStampInMs).ToList();

      ////delete zerro datasets
      //sortedDataStructureListW.RemoveAll(x => x.TimeStampInMs == 0);

      ////delete older datasets
      //sortedDataStructureListW.RemoveAll(x => x.TimeStampInMs <= lastRetrievedBufferTimeStampW);

      // parse all horizontal data
      var nrOfLinesProcessed = 0;
      foreach (var datastructure in sortedDataStructureListW)
      {
        ////first check if timestamp is newer than the last processed buffer
        //if (datastructure.TimeStampInMs <= lastRetrievedBufferTimeStampW)
        //{
        //  DebugLogging.WriteLine("Width: Skip buffer, timestamp {0} is same or older then last processed buffer {1}", datastructure.TimeStampInMs, lastRetrievedBufferTimeStampW);
        //  continue;
        //}

        int nrOfLinesDiff;
        if (firstTimeStampW)
        {
          nrOfLinesDiff = 1;
          firstTimeStampW = false;
        }
        else
        {
          nrOfLinesDiff = (int)((datastructure.TimeStampInMs - lastRetrievedBufferTimeStampW) / sampleTime);//how many samples between last fetch and this
          var remainder = (datastructure.TimeStampInMs - lastRetrievedBufferTimeStampW) % sampleTime;
          if (remainder == (sampleTime - 1))
          {
            nrOfLinesDiff++;
          }
        }
        if (nrOfLinesDiff > 1)
        {
          DebugLogging.WriteLine("Width: ## Missed {0} Lines", nrOfLinesDiff - 1);
          droppedLinesW += nrOfLinesDiff - 1;
        }

        //process data
        lastRetrievedBufferTimeStampW = datastructure.TimeStampInMs;
        //DebugLogging.WriteLine("--- Width: Process buffer with timestamp {0}", datastructure.TimeStampInMs);
        //store this data
        twW.WriteLine("{0};{1};{2};", datastructure.TimeStampInMs, datastructure.PositionInMs, datastructure.GetDataString());
        scannedLinesW++;
        nrOfLinesProcessed++;
      }
      DebugLogging.WriteLine("Width: Processed {0} Lines", nrOfLinesProcessed);
    }

    /* process Height data */
    if (registersImageH == null)
    {
      DebugLogging.WriteLine("Warning: Height, failed to fetch!");
    }
    else
    {
      //first store the received register data into DataStructure List
      var dataStructureListH = new List<DataStructure>();
      for (var i = 0; i < NrOfBuffersUsed; i++)
      {
        dataStructureListH.Add(RetrieveDataBuffer(registersImageH, (NrOfRegistersPerBufferH * i), NrOfVerticalBits));
      }

      //delete zerro and older datasets
      dataStructureListH.RemoveAll(x => x.TimeStampInMs == 0 || x.TimeStampInMs <= lastRetrievedBufferTimeStampH);

      //order list by timestamp
      var sortedDataStructureListH = dataStructureListH.OrderBy(o => o.TimeStampInMs).ToList();

      ////delete zerro datasets
      //sortedDataStructureListH.RemoveAll(x => x.TimeStampInMs == 0);

      ////delete older datasets
      //sortedDataStructureListH.RemoveAll(x => x.TimeStampInMs <= lastRetrievedBufferTimeStampH);

      // parse all vertical data
      var nrOfLinesProcessed = 0;
      foreach (var datastructure in sortedDataStructureListH)
      {
        ////first check if timestamp is newer than the last processed buffer
        //if (datastructure.TimeStampInMs <= lastRetrievedBufferTimeStampH)
        //{
        //  DebugLogging.WriteLine("Height: Skip buffer, timestamp {0} is same or older then last processed buffer {1}", datastructure.TimeStampInMs, lastRetrievedBufferTimeStampH);
        //  continue;
        //}

        int nrOfLinesDiff;
        if (firstTimeStampH)
        {
          nrOfLinesDiff = 1;
          firstTimeStampH = false;
        }
        else
        {
          nrOfLinesDiff = (int)((datastructure.TimeStampInMs - lastRetrievedBufferTimeStampH) / sampleTime);//how many samples between last fetch and this
          var remainder = (datastructure.TimeStampInMs - lastRetrievedBufferTimeStampH) % sampleTime;
          if (remainder == (sampleTime - 1))
          {
            nrOfLinesDiff++;
          }
        }
        if (nrOfLinesDiff > 1)
        {
          DebugLogging.WriteLine("Height: ## Missed {0} Lines", nrOfLinesDiff - 1);
          droppedLinesH += nrOfLinesDiff - 1;
        }

        //process data
        lastRetrievedBufferTimeStampH = datastructure.TimeStampInMs;
        //DebugLogging.WriteLine("--- Height: Process buffer with timestamp {0}", datastructure.TimeStampInMs);
        //store this data
        twH.WriteLine("{0};{1};{2};", datastructure.TimeStampInMs, datastructure.PositionInMs, datastructure.GetDataString());
        scannedLinesH++;
        nrOfLinesProcessed++;
      }
      DebugLogging.WriteLine("Height: Processed {0} Lines", nrOfLinesProcessed);
    }

    if (Helpers.TimeDiffInMs(DateTime.Now, lastStatusUpdateTime) > StatusUpdateTimeInMs)
    {
      //send capture status
      lastStatusUpdateTime = DateTime.Now;
      bgw.ReportProgress(-1,
        new StringEventArgs(string.Format("Horizontal: {0}/{1}   Vertical: {2}/{3} [dropped lines/total]",
          droppedLinesW, scannedLinesW, droppedLinesH, scannedLinesH)));
    }
    DebugLogging.WriteLine("ProcessTime={0} ms", Helpers.TimeDiffInMs(DateTime.Now, lastCaptureTime));
  }
  //stop capturing data
  twW.Flush();
  twW.Close();
  twH.Flush();
  twH.Close();
}

Normaly提取数据需要大约7 ms,但在时间戳10:07:04:833,你可以看到它花了45毫秒。这种延迟不在Backgroundworker Thread中。 记录:

10:07:04:766 *** Fetch all buffers
10:07:04:767 RegistersGet(modbusAddress=02, index=600, size=98)
10:07:04:767 ModbusMsg Send: 06 98 00 00 00 06 02 03 02 58 00 62 
10:07:04:769 ModbusMsg Received: 06 98 00 00 00 c6 02 03 00 85 06 b8 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 bd 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c2 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c7 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 cc 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 ae 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 b3 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 
10:07:04:770 RegistersGet succedded
10:07:04:770 RegistersGet(modbusAddress=02, index=740, size=70)
10:07:04:770 ModbusMsg Send: 06 99 00 00 00 06 02 03 02 e4 00 46 
10:07:04:772 ModbusMsg Received: 06 99 00 00 00 8e 02 03 00 85 06 b9 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 be 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c3 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c8 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 cd 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 af 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 b4 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 
10:07:04:772 RegistersGet succedded
10:07:04:773 *** Fetch all buffers, ready, FetchTime=7; timeDiff=22 ms
10:07:04:773 Width: Processed 5 Lines
10:07:04:774 Height: Processed 4 Lines
10:07:04:776 ProcessTime=3 ms
10:07:04:788 *** Fetch all buffers
10:07:04:788 RegistersGet(modbusAddress=02, index=600, size=98)
10:07:04:789 ModbusMsg Send: 06 9a 00 00 00 06 02 03 02 58 00 62 
10:07:04:810 ModbusMsg Received: 06 9a 00 00 00 c6 02 03 00 85 06 db 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 e0 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c2 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c7 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 cc 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 d1 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 d6 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 
10:07:04:828 RegistersGet succedded
10:07:04:828 RegistersGet(modbusAddress=02, index=740, size=70)
10:07:04:829 ModbusMsg Send: 06 9b 00 00 00 06 02 03 02 e4 00 46 
10:07:04:831 ModbusMsg Received: 06 9b 00 00 00 8e 02 03 00 85 06 ff 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 07 04 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 07 09 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 eb 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 f0 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 f5 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 fa 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 
10:07:04:833 RegistersGet succedded
10:07:04:833 *** Fetch all buffers, ready, FetchTime=45; timeDiff=60 ms
10:07:04:834 Width: Processed 4 Lines
10:07:04:835 Height: ## Missed 5 Lines
10:07:04:836 Height: Processed 7 Lines

1 个答案:

答案 0 :(得分:0)

同时拥有响应式用户界面和严格的实时硬件驱动程序(Modbus主控)很难。正确,可维护的解决方案是使用非垃圾收集语言编写硬件驱动程序,并使用不再实时的托管API将其粘贴到应用程序。

如果您不想/不能进行如此激烈的重新设计,请尝试reconfigure the garbage collector以更好地满足您的需求。把它放在你的启动代码中(WinForms的静态Main方法,WPF的App.OnStartup):

$5