2013-07-26 24 views
5

Tôi có một chuỗi công nhân, khi nó chấm dứt, báo hiệu một sự kiện. Sự kiện này sau đó được marshalled trên thread chính để notifiy nó chấm dứt thread của công nhân. Khi chuỗi công nhân gặp một ngoại lệ không được xử lý, tôi muốn ngoại lệ này được xử lý bởi hệ thống xử lý lỗi của luồng chính. Do đó, chuỗi công nhân đặt thuộc tính cho biết kết thúc không mong muốn của nó và lưu ngoại lệ trong thuộc tính khác, sau đó báo hiệu sự kiện và lần thoát.Ngoại lệ gì để ném khi thoát khỏi chuỗi bất ngờ?

Sau khi sự kiện đã được marshalled qua chủ đề chính, tôi muốn ném một ngoại lệ mới với ngoại lệ ban đầu được thiết lập như là ngoại lệ bên trong. Câu hỏi của tôi là: Loại ngoại lệ mới này là gì? Có một System.somethingException cụ thể cho loại tình huống, tôi nên thiết kế lớp ngoại lệ của riêng tôi cho tình huống cụ thể này, hoặc sẽ ném một System.Exception tiêu chuẩn với một thông điệp thích hợp được coi là thích hợp?

C# mã -psuedo:

class MyThread 
{ 
    public TerminationState Termination { get; private set; } 
    public Exception UncaughtException { get; private set; } 

    public delegate void ThreadTerminatedDelegate(MyThread thread); 
    public event ThreadTerminatedDelegate ThreadTerminated; 

    private void run() 
    { 
     try 
     { 
      doSomeWork(); 
     } 
     catch(Exception e) 
     { 
      UncaughtException = e; 
      Termination = TerminationState.AbortOnException; 
      ThreadTerminated(this); 
      return; 
     } 
     Termination = TerminationState.NormalTermination; 
     ThreadTerminated(this); 
    } 
} 

class MainThread 
{ 
    private MyThread myThread = new MyThread(); 

    private void run() 
    { 
     myThread.ThreadTerminated += handleTermination; 
     myThread.Start(); 
    } 

    private void handleTermination(MyThread thread) 
    { 
     if (InvokeRequired) 
     { 
      MyThread.ThreadTerminatedDelegate cb = new MyThread.ThreadTerminatedDelegate(handleTermination); 
      BeginInvoke(cb, new object[] { thread }); 
     } 
     else 
     { 
      if (thread.Termination == TerminationState.AbortOnException) 
      { 
       if (isFatal(thread.UncaughtException)) 
        throw new Exception("", thread.UncaughtException); //what to do here? 
       else 
        fixTheProblem(); 
      } 
      else 
      { 
       //normal wrapping up 
      } 
     } 
    } 
} 
+0

Tôi muốn nói rằng điều đó phụ thuộc vào những gì chuỗi đang thực hiện.Trên thực tế tôi không thích AggregateException rằng tất cả mọi thứ bằng phẳng để một lỗi chung chung để nuốt các ngoại lệ ban đầu cho cái gì khác ... không nhìn ý tưởng tốt như vậy. Tôi sẽ sao chép nó (để giữ lại dấu vết ngăn xếp ban đầu) và tôi sẽ làm lại nó. Nhưng đó chỉ là ý kiến ​​của tôi ... –

+0

Chính xác điều gì bạn hy vọng sẽ xảy ra khi bạn ném ngoại lệ một lần nữa? Tỷ lệ 99% là chương trình của bạn sẽ bị lỗi. Đó là một điều tốt, một cái gì đó đã không được thực hiện và bạn không có hy vọng làm cho nó được thực hiện. Nhưng sau đó, chỉ cần không bận tâm để bắt ngoại lệ ở nơi đầu tiên. Nó sẽ sụp đổ là tốt, nhưng ít nhất bạn sẽ nhận được một chẩn đoán tốt hơn và không phải viết mã vô dụng. –

+0

@Adriano Thay vì sao chép và làm lại, bạn không thể chỉ sử dụng 'ném;'? Điều đó giữ dấu vết ngăn xếp ban đầu, phải không? – JSQuareD

Trả lời

1

Tôi tin rằng bạn có thể thực hiện tất cả các ngoại lệ cần thiết xử lý đối với trường hợp ngoại lệ nền unhandled bằng cách thực hiện công việc hậu trường trong một Task và sau đó xử lý bất kỳ trường hợp ngoại lệ trong một sự tiếp nối của nhiệm vụ đó mà được lên lịch rõ ràng để chạy trên chuỗi chính. Có các tùy chọn bổ sung mà bạn có thể chỉ định cho việc tiếp tục, nhưng điều này sẽ bao gồm kịch bản của bạn.

Task.Factory.StartNew(
    () => 
    { 
     // Do some work that may throw. 
     // This code runs on the Threadpool. 
     // Any exceptions will be propagated 
     // to continuation tasks and awaiters 
     // for observation. 
     throw new StackOverflowException(); // :) 
    } 
).ContinueWith(
    (a) => 
    { 
     // Handle your exception here. 
     // This code runs on the thread 
     // that started the worker task. 
     if (a.Exception != null) 
     { 
      foreach (var ex in a.Exception.InnerExceptions) 
      { 
       // Try to handle or throw. 
      } 
     } 
    }, 
    CancellationToken.None, 
    TaskContinuationOptions.None, 
    TaskScheduler.FromCurrentSynchronizationContext() 
); 

Một liên kết hữu ích khác là MSDN's Asyncronous Programming Patterns. Nó xác định 3 cách chính để triển khai các hoạt động không đồng bộ trong một ứng dụng. Triển khai hiện tại của bạn nghe giống nhất với bài viết gọi EAP (Mẫu không đồng bộ dựa trên sự kiện).

Cá nhân tôi thích TAP (Mô hình không đồng bộ dựa trên nhiệm vụ) dựa trên .NET 4.0 TPL (Thư viện song song tác vụ). Nó cũng có giá trị làm chủ do sự đơn giản của cú pháp của nó và khả năng mở rộng của nó.

Từ MSDN:

  • Asynchronous Programming mẫu hoa văn (APM) (còn gọi là mô hình IAsyncResult), nơi hoạt động không đồng bộ đòi hỏi Begin và phương pháp End (ví dụ, BeginWrite và EndWrite cho các hoạt động ghi không đồng bộ). Mẫu này không còn được đề xuất cho phát triển mới nữa. Để biết thêm thông tin, hãy xem Mô hình lập trình không đồng bộ (APM).
  • Mẫu không đồng bộ dựa trên sự kiện (EAP), yêu cầu phương thức có hậu tố Async và cũng yêu cầu một hoặc nhiều sự kiện, loại ủy quyền xử lý sự kiện và loại bắt nguồn từ EventArg. EAP đã được giới thiệu trong .NET Framework 2.0. Nó không còn được khuyến khích cho phát triển mới. Để biết thêm thông tin, hãy xem Mẫu không đồng bộ dựa trên sự kiện (EAP).
  • Mẫu không đồng bộ dựa trên nhiệm vụ (TAP), sử dụng một phương pháp duy nhất để trình bày việc bắt đầu và hoàn thành một thao tác không đồng bộ. TAP đã được giới thiệu trong .NET Framework 4 và là phương pháp được đề xuất cho lập trình không đồng bộ trong .NET Framework. Để biết thêm thông tin, hãy xem Mẫu không đồng bộ dựa trên nhiệm vụ (TAP).

Ngoài ra, đừng quên lớp đáng tin cậy BackgroundWorker. Lớp học này là một yếu tố quan trọng đối với tôi trong một thời gian dài và mặc dù nó đã trở nên hơi bị phản đối bởi TAP, nhưng nó vẫn sẽ hoàn thành công việc và rất dễ hiểu và dễ sử dụng.

// Create a new background worker. 
var bgw = new BackgroundWorker(); 

// Assign a delegate to perform the background work. 
bgw.DoWork += (s, e) => 
    { 
     // Runs in background thread. Unhandled exceptions 
     // will cause the thread to terminate immediately. 
     throw new StackOverflowException(); 
    }; 

// Assign a delegate to perform any cleanup/error handling/UI updating. 
bgw.RunWorkerCompleted += (s, e) => 
    { 
     // Runs in UI thread. Any unhandled exception that 
     // occur in the background thread will be accessible 
     // in the event arguments Error property. 
     if (e.Error != null) 
     { 
      // Handle or rethrow. 
     } 
    }; 

// Start the background worker asynchronously. 
bgw.RunWorkerAsync(); 
+0

Cảm ơn bạn đã trả lời! Ngay bây giờ tôi đang đi nghỉ nên tôi không thực sự có thời gian để xem nó. Khi tôi quay lại vào tuần tới, tôi sẽ xem xét chi tiết và chấp nhận câu trả lời nếu nó giải quyết được vấn đề. :) – JSQuareD

+1

Đúng, đây là giải pháp thay thế thanh lịch để hack xấu xí của tôi, cảm ơn! Ngoài ra, cảm ơn sự giám sát của các mẫu lập trình không đồng bộ khác nhau, tôi đã bắt đầu đọc "C# trong một nutshell", và có lẽ sẽ làm việc theo cách của tôi thông qua những điều này trong thời gian tới. :) – JSQuareD

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