2011-01-25 41 views
6

Trong ứng dụng dịch vụ Windows của tôi, tôi đang sử dụng bộ hẹn giờ rất nhiều. Tôi chỉ sử dụng System.Timers. Tôi chưa bao giờ trải qua vấn đề này trước đây, nhưng đột nhiên tôi nhận được ngoại lệ này:.NET 3.5 C# Lỗi với System.Timer System.ObjectDisposedException: Không thể truy cập đối tượng được xử lý

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() 

Trong phương pháp của tôi, tôi đang dừng bộ đếm thời gian, và thay đổi khoảng thời gian hẹn giờ. Đó là nơi tôi có ngoại lệ.

Tôi đã đọc nội dung nào đó về lỗi này nhưng vẫn còn dễ bị lỗi này ngay cả trong .NET 3.5 không?

Làm cách nào để khắc phục sự cố? Tôi có nên gia hạn đối tượng bộ đếm thời gian sau khi dừng và đặt khoảng thời gian cho một đối tượng mới không? Tôi đang sử dụng GC.KeepAlive (dataTimer);

Edit: Tôi tìm thấy một số câu hỏi khác về vấn đề này:

* Tôi tìm thấy một liên kết http://www.kbalertz.com/kb_842793.aspx Về cơ bản ngay sau khi bạn dừng lại một bộ đếm thời gian, nội System.Threading.Timer trở nên có sẵn cho Bộ sưu tập rác, đôi khi gây ra sự kiện trôi qua không xảy ra, hoặc đôi khi gây ra ngoại lệ tham chiếu được xử lý. Mặc dù không được mô tả trong bài viết, giải pháp của tôi là để tạo bộ hẹn giờ mới mỗi khi bộ hẹn giờ được dừng lại và thêm lại các sự kiện đã trôi qua. Không hiệu quả nhưng dễ dàng, và không phải là một vấn đề xử lý-khôn ngoan với tôi. Điều này đã giải quyết được hoàn toàn vấn đề của tôi. Chúc mừng cho tất cả những ai trả lời. *

Nhưng tôi bối rối là tại sao lỗi vẫn còn đó, và tôi cần phải chắc chắn rằng lại thêm bộ đếm thời gian là một ý tưởng tốt ...

Mã mà gây ra lỗi:

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(); 
} 

Chức năng được gọi là từ sự kiện SerialPortDataReceived:

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

hẹn giờ đã được ngừng lại trước khi gọi thay đổi khoảng thời gian.

Timer là lĩnh vực riêng của lớp học của tôi:

private Timer asyncResponseTimer = new Timer(); 

EDIT: Ứng dụng này đã được chạy trong nhiều tháng liên tiếp và đây là lần đầu tiên tôi nhận được ngoại lệ này!

mô hình xử lý của tôi:

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

Hãy cung cấp cho chúng tôi mã của bạn cũng như thông báo lỗi. Đoán của tôi là bạn đang sử dụng khối "đang sử dụng" tự động loại bỏ thứ gì đó khi kết thúc khi bạn không nên như vậy. Chúng tôi sẽ xem xét mã của bạn và cố gắng cho bạn biết. – Chris

+2

Đối với những gì nó có giá trị kỹ thuật của tôi khi sử dụng bộ đếm thời gian là để giữ một tham chiếu đến họ xung quanh một nơi nào đó (ví dụ như một lĩnh vực tư nhân hoặc bộ sưu tập của bộ đếm thời gian) để tôi biết vẫn còn có tài liệu tham khảo. theo cách đó tôi biết họ sẽ không bị GC trước khi tôi muốn. Mặc dù bạn làm sau đó tất nhiên phải chắc chắn rằng bạn loại bỏ tham chiếu đó khi bạn đang thực hiện với đối tượng bộ đếm thời gian. – Chris

+0

Tôi có hẹn giờ được tham chiếu là thành viên riêng tư của lớp học. – Simon

Trả lời

1

Nó có thể được rằng bạn nhận được dữ liệu cổng nối tiếp ngay sau khi bạn đã vứt bỏ bộ đếm thời gian của bạn? Đó là điều duy nhất đến với tâm trí của tôi với dữ liệu bạn đã đăng! Bạn đang làm gì trong Stop()! phương thức bên trong Dispose() ????

+0

Tôi không bao giờ gọi hàm timer.Dispose(). Tôi cần Stop() để dừng giao tiếp cổng nối tiếp. Tôi cũng có phương thức Start(). Khi tôi xử lý lớp SerialPortCommunication, tôi cũng dừng hẹn giờ để ngăn chặn xảy ra sau khi vứt bỏ, bởi vì nó là trên thread khác nhau. Ngoại lệ đó KHÔNG được nâng lên khi vứt bỏ. Nó happend ở giữa giao tiếp với cổng nối tiếp. Đặt lại khoảng thời gian của bộ hẹn giờ được gọi mỗi khi SerialPortDataReceived() xảy ra. – Simon

+0

xem các chỉnh sửa của tôi. – Simon

1

Dường như bạn khởi động bộ hẹn giờ khi nhận dữ liệu trên cổng nối tiếp. Điều gì sẽ xảy ra nếu bạn nhận được dữ liệu bổ sung trên cổng trước khi bộ hẹn giờ kết thúc gửi phản hồi? Dường như, dựa trên thông tin bạn đã đăng, khoảng thời gian hẹn giờ sẽ được thay đổi và bắt đầu (lại) trong khi bộ hẹn giờ vẫn đang xử lý sự kiện hẹn giờ của nó.

Bạn đã cân nhắc kịch bản trên chưa? Là AutoReset hẹn giờ hay không? Khi nào bạn gọi Stop()?

+0

Bộ hẹn giờ ở đó để xác định xem không có dữ liệu nào nhận được. Vì vậy, bộ đếm thời gian được khởi động lại everytime serialPortDataReceived xảy ra. Nếu bộ đếm thời gian kết thúc công việc của mình, tôi sẽ biết rằng tất cả dữ liệu được nhận và tôi có thể tiếp tục gửi yêu cầu. Bộ hẹn giờ có AutoReset mặc định = true. Tôi đang gọi Stop() chỉ khi tôi muốn ngừng giao tiếp cổng nối tiếp, và khi tôi nhận được ngoại lệ đó Stop() KHÔNG được gọi. Cơ bản được gọi bởi người dùng từ giao diện người dùng. – Simon

1

Vì bạn chưa chỉ định cấu hình máy chủ của mình, tôi giả sử Windows Server 2003. Khi bạn đề cập đến nó đã hoạt động (gần hai tháng), nó nhắc nhở số 49.7 days bug. Nó có thể không áp dụng được cho kịch bản của bạn, trừ khi nó lại bị treo vào tháng 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.

KeepAlive() không hữu ích ở đây vì bạn đã khai báo bộ đếm giờ ở cấp lớp - điều này tốt. Nó không phải là cần thiết để ngừng bộ đếm thời gian để thay đổi khoảng thời gian.

Từ ngăn xếp cuộc gọi và mã bạn đã cung cấp, có vẻ như bạn đang cố thay đổi khoảng thời gian trên bộ hẹn giờ đã được xử lý. Bạn có thể cần phải ngừng bộ đếm thời gian sau khi xác nhận không còn việc phải làm, thay vì dừng nó trong mẫu vứt bỏ của bạn mà dường như ảnh hưởng đến công việc đang diễn ra. Tức là, trước tiên bạn kiểm tra xem có còn phải thực hiện công việc nữa hay không, nếu không, hãy dừng nghe cổng và sau đó dừng hẹn giờ. Nó sẽ không có nhiều trợ giúp trừ khi tôi có thể thấy một số phần khác của mã - như trình xử lý sự kiện, khai báo serialPortManager, v.v.

Các vấn đề liên quan