2011-01-25 61 views
6

在我的Windows服務應用程序中,我使用了很多計時器。我只使用System.Timers。 我以前從來沒有遇到過這個問題,但突然我得到這個異常:.NET 3.5 C#與System.Timer錯誤System.ObjectDisposedException:無法訪問處置對象

System.ObjectDisposedException: Cannot access a disposed object. 
    at System.Threading.TimerBase.ChangeTimer(UInt32 dueTime, UInt32 period) 
    at System.Threading.Timer.Change(Int32 dueTime, Int32 period) 
    at System.Timers.Timer.UpdateTimer() 
    at System.Timers.Timer.set_Interval(Double value) 
    at MyApp.MySpace.MySpace2.MyClassWithTimer.MethodChangeTimerInterval() 

在我的方法,我停止計時器,並改變定時器的時間間隔。那是我得到例外的地方。

我已經讀過關於這個bug的一些信息,但是即使在.NET 3.5中也有這個bug嗎?

我該如何解決?我應該在停止後更新計時器對象並將間隔設置爲新對象嗎?我正在使用GC.KeepAlive(dataTimer);

編輯: 我發現關於這個問題的一些其他問題:

*我找到了一個鏈接 http://www.kbalertz.com/kb_842793.aspx 基本上只要你停止計時器,內部 System.Threading.Timer變爲可用於垃圾收集, 有時會導致過期事件不發生,或者有時導致處置的參考異常 。 儘管在文章中沒有描述,我的解決方案是 創建一個新的計時器,每當計時器停止並重新添加已過去的事件。效率不高,但容易, ,對我來說不是處理器方面的問題。 這完全解決了我的問題。 乾杯所有誰回答。*

但我很困惑,爲什麼這個錯誤仍然存​​在,我需要,以確保重新添加定時器是一個好主意......

代碼造成錯誤:

private void StartAsyncResponseTimer() 
{ 
    switch (_lastRequestType) 
    { 
     case 1: 
      asyncResponseTimer.Interval = 1000; 
      break; 
     case 2: 
      asyncResponseTimer.Interval = 2000; 
      break; 
     case 3: 
      asyncResponseTimer.Interval = 3000; 
      break; 
     default: 
      asyncResponseTimer.Interval = 10000; 
      break; 
    } 

    asyncResponseTimer.Start(); 
} 

功能從SerialPortDataReceived事件稱爲:

private void SerialPortDataReceived(object sender, EventArgs e) 
{ 
     StartAsyncResponseTimer(); 
} 

定時器在呼喚改變區間之前停止。

定時器是我的類的私有領域:

private Timer asyncResponseTimer = new Timer(); 

編輯:行中的應用程序已經運行了數月,這是我第一次得到這個例外!

我的Dispose模式:

public class SerialPortCommunication{ 

... 

    private void SerialPortDataReceived(object sender, EventArgs e) 
    { 
     ReadResponse(); 

     StartAsyncResponseTimer(); 
    } 

    //used to determine if is recieving response over 
    private void StartAsyncResponseTimer() 
    { 
     switch (_lastRequestType) 
     { 
      case 1: 
       asyncResponseTimer.Interval = 1000; 
       break; 
      case 2: 
       asyncResponseTimer.Interval = 2000; 
       break; 
      case 3: 
       asyncResponseTimer.Interval = 3000; 
       break; 
      default: 
       asyncResponseTimer.Interval = 10000; 
       break; 
     } 

     asyncResponseTimer.Start(); 
    } 

    public virtual void Dispose() 
    { 

     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    private void Dispose(bool disposing) 
    { 
     if (!this._disposed) 
     { 
      if (disposing) 
      { 
       // Dispose managed resources. 

      } 

      // Dispose unmanaged resources. 
      _disposed = true; 

      Stop(); 

     } 
    } 

    ~SomeClass() 
    { 

     Dispose(false); 
    } 

    #endregion 




    public void Stop() 
    { 
     _asyncResponseTimer.Stop(); 
     serialPortManager.ClosePort(); 
    } 
} 
+0

給我們您的代碼以及錯誤消息。我的猜測是你正在使用一個「使用」塊,當你不應該完成時,它會自動處理一些東西。我們會看看你的代碼,儘量告訴你。 – Chris 2011-01-25 12:59:20

+2

使用計時器時,我的技術的價值在於在某處(例如私人字段或定時器集合)保留對它們的引用,以便我知道仍然有引用。這樣,我知道他們不會在我想要之前被GCed。雖然你當然必須確保在完成計時器對象時刪除該引用。 – Chris 2011-01-25 13:01:06

+0

我有定時器引用爲類的私有成員。 – Simon 2011-01-25 13:07:29

回答

1

它可以是你得到你已經設置你的計時器只是後串口數據?這是唯一讓我想起你發佈的數據!你在Stop()做什麼? Dispose()中的方法?

1

看起來像你在串口接收數據時開始計時。如果在定時器完成發送響應之前,您在端口上收到其他數據會發生什麼情況?看起來,根據您發佈的信息,定時器間隔將在定時器仍在處理定時器事件時更改並啓動(再次)。

您是否考慮過上述情況?定時器AutoReset或不?你什麼時候打電話給Stop()?

1

由於您尚未指定服務器配置,因此我假定使用Windows Server 2003.當您提及它工作了(幾乎)兩個月時,它會提醒您49.7 days bug。它可能不適用於你的情況,除非它在3月份再次崩潰。這是很好的 - :-)

Symptom 2
On a Windows Server 2003-based computer that is not running ISA Server, a similar problem occurs when the following conditions are true: You call the CreateTimerQueueTimer function repeatedly in an application. You set a specified period to trigger the timer that is created by the CreateTimerQueueTimer function.

The application runs for more than 49.7 days. After 49.7 days, the timer is triggered immediately instead of being triggered after the specified period. After several minutes, the timer is triggered correctly.

保持活動(),因爲你宣佈在類級別的計時器是不是在這裏非常有用。沒有必要停止改變間隔的定時器。

從調用堆棧和您提供的代碼看來,您似乎正在嘗試更改已處理計時器的時間間隔。在確認沒有其他工作要做之後,您可能需要停止計時器,而不是在處理模式中停止計時,這似乎會干擾正在進行的工作。也就是說,首先檢查是否還有工作要做,如果沒有,則停止監聽端口,然後停止計時器。除非我能看到代碼的更多部分 - 比如事件處理程序,serialPortManager聲明等,否則它不會有太多幫助。

相關問題