2016-01-14 61 views
1

我有一個Backgroundworker從UPD設備收集數據。我需要每隔35秒從te設備獲取數據,否則它將被覆蓋。問題是我每+/- 5秒鐘就錯過了一些數據。如果我查看跟蹤中生成的時間戳,我會看到延遲在backgroundworker線程之外。 我通過在需要時刷新Trace日誌和兩個文本編寫器對象來提高性能。c#backgroundworker被.Net任務中斷?

有沒有人知道延遲的原因是什麼?

這裏是我的代碼:

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毫秒,但在時間戳10:07:04:833,你可以看到它抽放45毫秒。此延遲不在Backgroundworker線程中。 日誌記錄:

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 
+0

你有沒有考慮使用自己的線程(不是BackgroundWorker的),並優先打?這說 - Windows不是一個實時的操作系統,C#不是實時的。 UDP設備不好,因爲它沒有緩衝。你有沒有在那裏檢查API?另類使用高精度回調 - 不是普通的後臺工作者。 – TomTom

+0

我想用Thread來代替,但在互聯網上閱讀告訴我這不會提高性能。我也加了 Thread.CurrentThread.Priority = ThreadPriority.Highest; 到後臺工作,沒有性能增加。 該設備具有緩衝區,並且每35毫秒它們已滿。 我試着製作更多的緩衝區,但後來我需要更多時間來獲取數據。 7個緩衝區具有最佳性能。 – Roy

+0

它只需要一個第2代垃圾收集來破壞你的「實時」保證。不是延遲的唯一來源,您的BGW線程也必須與其他進程擁有的其他線程競爭。 Windows工作站版本上的默認線程量是中斷速率的3倍。 3×15.625〜= 45毫秒。你只能使用timeSetEvent()和一個小心鎖定的機器來使用本機代碼。或者是設備驅動程序。 –

回答

0

既具有快速響應的用戶界面,並在同一時間嚴格的實時硬件驅動程序(Modbus主機)是很難的。適當的,可維護的解決方案是使用非垃圾收集語言編寫硬件驅動程序,並使用不再實時的託管API將其粘貼到應用程序。

如果你不想/不能做出如此激烈的重新設計,請嘗試reconfigure the garbage collector以更好地滿足你的需求。把你的啓動代碼(靜態主要針對的WinForms WPF的方法,App.OnStartup):

System.Runtime.GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency; 
+0

謝謝大家的回覆。 我擔心在目前的實現中,我已經處於非實時系統的極限了。如果我們放棄幾條線是不可取的,那麼我將不得不重新設計整個系統。 謝謝大家! – Roy