2011-10-20 30 views
5

Trong một ứng dụng tôi đang phát triển, tôi có một biểu mẫu chính chỉ đơn giản là ngồi đó và hiển thị dữ liệu nhật ký, và một chuỗi công nhân tự động thực hiện công việc trong một vòng lặp.Gracefully shutdown thread

MyWorker worker = new MyWorker(); 
MainForm mainForm = new MainForm(); 

// Subscribe form to log event so log data gets displayed 
worker.Log += mainForm.Log; 

// Start the worker thread's MainLoop 
new Thread(new ThreadStart(worker.MainLoop)).Start(); 

// Show the form (blocking) 
Application.Run(mainForm); 

// If we end up here, the form has been closed and the worker has to stop running    
worker.Running = false; 

Như bạn có thể thấy, bất cứ khi nào biểu mẫu được đóng, chuỗi công nhân phải dừng lại. Công nhân trông giống như sau:

public class MyWorker 
{ 
    public String Running { get; set; } 

    public MyWorker() 
    { 
     Running = true; 
    } 

    public void MainLoop() 
    { 

     while (Running) 
     { 

      DoExtensiveWork1(); 
      if (!Running) return; 

      DoExtensiveWork2(); 
      if (!Running) return; 

      DoExtensiveWork3(); 
      if (!Running) return; 

      DoExtensiveWork4(); 
      if (!Running) return; 

      DoExtensiveWork5();   
      if (!Running) return; 

      // We have to wait fifteen minutes (900 seconds) 
      // before another "run" can be processed 
      for (int i = 0; i < 900; i++) 
      { 
       Thread.Sleep(1000); 
       if (!Running) return; 
      } 
     } 
    } 
} 

Như bạn thấy, tôi muốn chủ đề có thể dừng khi chuyển đổi giữa các hoạt động liên tiếp, nhưng không phải khi hoạt động. Khi một hoạt động (DoExtensiveWorkN) kết thúc, trạng thái và kết quả của nó được duy trì làm đĩa hoặc cơ sở dữ liệu, vì vậy thoát trong khi đang hoạt động (ví dụ: Thread.Abort) không phải là một tùy chọn.

Tuy nhiên, tôi tìm thấy mã này tôi vừa viết để xem, đặc biệt là "vòng lặp chờ" ngủ 900 giây, để ngăn chặn chuỗi không hoạt động trong 15 phút trước khi phát hiện Running được đặt thành false.

Tôi muốn có thể ném một số loại sự kiện để dừng vòng lặp chính ngay sau khi hoàn thành một tác phẩm.

Bất cứ ai có thể chỉ cho tôi đúng hướng để làm điều này, hoặc nếu viết lại toàn bộ là bắt buộc vì tôi hoàn toàn hiểu lầm luồng, hãy chỉ cho tôi một nơi nào đó mà các nguyên tắc đó được giải thích?

Trả lời

13

Bạn có thể dọn dẹp cả việc chạy các tác vụ riêng lẻ và vòng lặp chờ 15 phút đáng kể.

tôi muốn đề nghị có lẽ sử dụng một cái gì đó như thế này:

public class MyWorker 
{ 
    private readonly ManualResetEvent _stopEvent = new ManualResetEvent(false); 
    private readonly Action[] _workUnits; 

    private bool Running 
    { 
     get { return !_stopEvent.WaitOne(0); } 
    } 

    public MyWorker() 
    { 
     _workUnits = new Action[] 
     { 
      DoExtensiveWork1, 
      DoExtensiveWork2, 
      DoExtensiveWork3, 
      DoExtensiveWork4, 
      DoExtensiveWork5 
     }; 
    } 

    public void Stop() 
    { 
     _stopEvent.Set(); 
    } 

    public void MainLoop() 
    { 

     while (Running) 
     { 
      foreach (var workUnit in _workUnits) 
      { 
       workUnit(); 
       if (!Running) return; 
      }   

      // We have to wait fifteen minutes (900 seconds) 
      // before another "run" can be processed 
      if (_stopEvent.WaitOne(900000)) return; 
     } 
    } 
} 

Sau đó, để ngăn chặn quá trình này tại thời điểm thích hợp tiếp theo:

Worker.Stop(); 
0

tôi sẽ đề nghị sử dụng System.Timers.Timer.

Bạn có thể thực hiện công việc của mình với điều đang chạy và thay vì sử dụng chế độ ngủ, bạn chỉ có thể đặt hẹn giờ sẽ tắt sau 15 phút.

Nếu bạn muốn dừng sớm, hãy gọi một số phương pháp hủy bỏ (tương tự như thiết lập biến Running = true của bạn) sẽ dừng hẹn giờ.

Cần lưu ý rằng mỗi khi sự kiện hẹn giờ kích hoạt nó sẽ khởi động một chuỗi mới, do đó bạn không cần phải lo lắng về việc hủy các chuỗi nền. Chủ đề của bạn kết thúc quá trình xử lý, thiết lập bộ đếm thời gian chạy trong 15 phút và sau đó luồng kết thúc tự nhiên. Nếu bạn hủy bỏ trong thời gian chờ đợi sau đó bạn chỉ cần thoát khỏi bộ đếm thời gian và không cần dọn dẹp thêm. Nếu bạn hủy bỏ trong khi chạy thì bạn để cho kết thúc chạy và cuối cùng nó kiểm tra một lá cờ và không bắt đầu hẹn giờ một lần nữa và sau đó thread kết thúc.

Đối với bộ hẹn giờ, bạn sẽ muốn đặt hẹn giờ để bắt đầu thủ công ở cuối quá trình. Phương án thay thế là có bộ đếm thời gian đánh dấu mỗi 15 phút nhưng điều đó có nghĩa là nếu quá trình xử lý của bạn mất 10 phút thì nó chỉ mất 5 phút trước lần chạy tiếp theo. Và nếu mất hơn 15 phút, bạn có thể gặp rắc rối. Đồng thời khởi động lại bộ hẹn giờ theo cách thủ công đảm bảo rằng quá trình xử lý sẽ không khởi động lại trong khi quá trình khác đang chạy.

+0

Bộ hẹn giờ sẽ không giải quyết được vấn đề chính mà tôi gặp phải: Tôi không muốn công việc tiếp tục khi biểu mẫu bị đóng và tôi không muốn thêm nhiều mã để tiếp tục kiểm tra. – CodeCaster

+0

@CodeCaster: Ah, tôi hiểu lầm "vì vậy bỏ trong khi một hoạt động đang được tiến hành (bởi, ví dụ, Thread.Abort) không phải là một lựa chọn" để có nghĩa là toàn bộ chủ đề. Suy nghĩ của tôi sau đó sẽ sử dụng một loạt các hành động nhưng Iridium đánh tôi với nó. Tôi vẫn thích bộ đếm thời gian chờ đợi 15 phút. :) – Chris

+0

Tôi có thể mô tả rõ ràng hơn. Nhờ đề nghị mặc dù. :-) – CodeCaster