2009-08-23 18 views
7

Xin chào mọi người!"Xử lý an toàn đã bị đóng" bằng SerialPort và một chuỗi trong C#

Tôi có ren này SerialPort trình bao bọc đọc trong một dòng từ cổng nối tiếp. Đây là mã của chủ đề của tôi.

protected void ReadData() 
{ 
    SerialPort serialPort = null; 
    try 
    { 
     serialPort = SetupSerialPort(_serialPortSettings); 
     serialPort.Open(); 

     string data; 
     while (serialPort.IsOpen) 
     { 
      try 
      { 

       data = serialPort.ReadLine(); 
       if (data.Length > 0) 
        ReceivedData(serialPort, new ReceivedDataEventArgs(data)); 

      } 
      catch (TimeoutException) 
      { 
       // No action 
      } 
     } 
    } 
    catch (ThreadAbortException) 
    { 
     if (serialPort != null) 
      serialPort.Close(); 
    } 
} 

khi tôi gọi myThread.Abort(); tôi nhận được một ngoại lệ (không có dòng hoặc tham chiếu đến code) "xử lý an toàn đã bị đóng cửa". Bất cứ ai có thể phát hiện ra những gì tôi đang làm sai? Cảm ơn.

Nhân tiện, tôi có Start()Stop() tạo chủ đề và hủy bỏ chủ đề một cách tôn trọng.

+0

Tôi đã thêm một số mã ví dụ –

Trả lời

10

Tôi nghi ngờ rằng đó là vì bạn đang sử dụng Thread.Abort để kết thúc luồng - thường bị cau mày. Hành vi chuỗi khi bạn hủy bỏ không thể dự đoán được. Do đó, vì cổng nối tiếp là một trình bao bọc trên mã nguồn gốc, có các tài nguyên gốc - được biểu diễn bằng một SafeHandle trong .NET - được xử lý bất ngờ và vì vậy bạn có được Ngoại lệ.

Bạn có thể suy nghĩ về những gì xảy ra với chủ đề của bạn như thế này:

  • bạn bắt đầu chủ đề của bạn
  • bạn mở cổng nối tiếp (trong đó phân bổ các nguồn lực tự nhiên và sử dụng SafeHandle (s) để giữ cho những nguồn lực)
  • bạn bắt đầu đọc từ cổng nối tiếp
  • sau đó tại một số điểm (bất ngờ vào chủ đề của bạn), bạn gọi Thread.Abort trên đó
  • hầu như các mã trong chủ đề của bạn là ở tha Điểm cố gắng truy cập vào cổng nối tiếp (để đọc dữ liệu)
  • chuỗi bị tiêu diệt và xử lý cổng nối tiếp bị phá hủy hoàn toàn
  • bạn nhận được một ngoại lệ được ném từ mã bên trong hàm ReadLine() của cổng nối tiếp vì tay cầm của nó không còn hợp lệ

Bạn thực sự nên sử dụng một phương pháp khác để hủy bỏ chuỗi sao cho bạn có cơ hội thích hợp để đóng và vứt bỏ cổng nối tiếp.

Một cách thích hợp để đóng chủ đề của bạn có thể được thực hiện bằng cách sử dụng ManualResetEvent như thế này:

protected ManualResetEvent threadStop = new ManualResetEvent(false); 

protected void ReadData() 
{ 
    SerialPort serialPort = null; 
    try 
    { 
     serialPort = SetupSerialPort(_serialPortSettings); 
     serialPort.Open(); 

     string data; 
     while (serialPort.IsOpen) 
     { 
      try 
      { 

       data = serialPort.ReadLine(); 
       if (data.Length > 0) 
        ReceivedData(serialPort, new ReceivedDataEventArgs(data)); 

      } 
      catch (TimeoutException) 
      { 
       // No action 
      } 

      // WaitOne(0) tests whether the event was set and returns TRUE 
      // if it was set and FALSE otherwise. 
      // The 0 tells the manual reset event to only check if it was set 
      // and return immediately, otherwise if the number is greater than 
      // 0 it will wait for that many milliseconds for the event to be set 
      // and only then return - effectively blocking your thread for that 
      // period of time 
      if (threadStop.WaitOne(0)) 
       break; 
     } 
    } 
    catch (Exception exc) 
    { 
     // you can do something here in case of an exception 
     // but a ThreadAbortedException should't be thrown any more if you 
     // stop using Thread.Abort and rely on the ManualResetEvent instead 
    } 
    finally 
    { 
     if (serialPort != null) 
      serialPort.Close(); 
    } 
} 

protected void Stop() 
{ 
    // Set the manual reset event to a "signaled" state --> will cause the 
    // WaitOne function to return TRUE 
    threadStop.Set(); 
} 

Tất nhiên, khi sử dụng phương pháp các sự kiện để ngăn chặn các chủ đề mà bạn phải cẩn thận để bao gồm một sự kiện kiểm tra trạng thái trong tất cả các vòng lặp hoặc nhiệm vụ chạy dài của bạn. Nếu bạn không có chủ đề của bạn có thể xuất hiện không đáp ứng với thiết lập của bạn sự kiện - cho đến khi nó được ra khỏi vòng lặp dài, hoặc nhiệm vụ và có cơ hội để "nhìn thấy" rằng sự kiện đã được thiết lập.

+0

Điều gì sẽ là cách thích hợp để đóng chuỗi của tôi. 'Stop()'/'Start()' được sử dụng khi tôi cấu hình lại cổng. –

+0

Có một số cách bạn có thể làm và tôi đã đưa ra một ví dụ bằng cách sử dụng ManualResetEvent, một cơ chế khá phổ biến .. –

+0

Ngọt ngào. Cảm ơn bạn! –

0

Chạy vào một tình huống tương tự nơi tôi đã cố gắng tạo các kết nối cổng nối tiếp cục bộ cho một phương thức duy nhất.

Ý tưởng là tạo tối đa bốn đối tượng serialPort (Đối với mỗi cổng nối tiếp). Khi một trong các cổng quay trở lại với dữ liệu tốt, tôi biết cổng của tôi đã được kết nối với thiết bị nào. Tôi muốn loại bỏ tất cả các đối tượng "dùng thử" của tôi và tạo một kết nối mới đến cổng com cụ thể.

Mỗi lần thông qua phương pháp tôi tạo/hủy đối tượng serialPort của mình. Rất tiếc. Nó xảy ra như vậy nếu GC đã không chạy theo thời gian tôi gọi phương pháp một lần nữa nó sẽ cố gắng để tạo ra một kết nối nối tiếp thứ hai thay thế kết nối đầu tiên và họ sẽ va chạm. Điều đó sẽ kích hoạt lỗi này.

Giải pháp: tạo tất cả các đối tượng kết nối cổng nối tiếp toàn cầu cho lớp. Ugly Hack: Có, nhưng nó hoạt động

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