6

Tôi muốn bắt đầu sử dụng Task Parallel Library, vì đây là khung được đề xuất để tiến hành các hoạt động không đồng bộ. Một điều tôi đã không thể tìm thấy là bất kỳ phương tiện của Abort buộc, chẳng hạn như những gì Thread.Abort cung cấp.Giết một Tác vụ bị khóa trong .NET 4 TPL

Mối quan tâm đặc biệt của tôi là tôi lên lịch các tác vụ đang chạy mã mà tôi không muốn hoàn toàn tin tưởng. Đặc biệt, tôi không thể chắc chắn mã không tin cậy này sẽ không bế tắc và do đó tôi không thể chắc chắn nếu một nhiệm vụ tôi lên lịch sử dụng mã này sẽ bao giờ hoàn thành. Tôi muốn tránh xa sự cô lập AppDomain thực sự (do sự phức tạp và phức tạp của marshaling), nhưng tôi cũng không muốn để lại một chuỗi Task treo xung quanh, bế tắc. Có cách nào để làm điều này trong TPL?

Trả lời

9

Cách thực hiện điều này là với một CancellationToken và mô hình hủy mới Mô hình hủy mới được tích hợp vào Khuôn khổ .NET trong một số loại. .Threading.Tasks.Task, System.Threading.Tasks.Task và System.Linq.ParallelEnumerable.

Đây là một ví dụ về vấn đề của bạn. Mã này sẽ luôn luôn bế tắc bởi vì các mã gọi điện thoại có một khóa đầu tiên và sau đó nhiệm vụ bế tắc cố gắng để nuôi dưỡng cùng một khóa.

public void Example() 
{ 
    object sync = new Object(); 
    lock (sync) 
    { 
     CancellationTokenSource canceller = new CancellationTokenSource(); 
    ManualResetEvent started = new ManualResetEvent(false); 
     Task deadlocked = Task.Factory.StartNew(() => 
      { 
      started.Set(); 
       // EVIL CODE: This will ALWAYS deadlock 
       lock(sync) { }; 
      }, 
      canceller.Token); 

     // Make sure task has started. 
    started.WaitOne(); 

     canceller.Cancel(); 

     try 
     { 
      // Wait for task to cancel. 
      deadlocked.Wait(); 
     } 
     catch (AggregateException ex) 
     { 
      // Ignore canceled exception. SIMPLIFIED! 
      if (!(ex.InnerException is TaskCanceledException)) 
       throw; 
     } 
    } 
} 

Hủy tác vụ trong TPL là hợp tác. Nói cách khác, điều này sẽ luôn luôn bế tắc bởi vì không có gì xử lý mã thông báo hủy được thiết lập để hủy bỏ vì chuỗi nhiệm vụ bị khóa.

Có một khoảng cách này nhưng nó vẫn dựa vào các tác giả của mã không tin cậy để làm điều đúng:

public static void Example2() 
{ 
    Mutex sync = new Mutex(true); 

    CancellationTokenSource canceller = new CancellationTokenSource(); 
    bool started = false; 

    Task deadlocked = Task.Factory.StartNew(() => 
     { 
      started = true; 
      // EVIL CODE: This will ALWAYS deadlock 
      WaitHandle.WaitAny(new WaitHandle[] { canceller.Token.WaitHandle, sync }); 
     }, 
     canceller.Token); 

    // Make sure task has started. 
    while (!started) { } 

    canceller.Cancel(); 

    try 
    { 
     // Wait for task to cancel. 
     deadlocked.Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     // Ignore canceled exception. SIMPLIFIED! 
     if (!(ex.InnerException is TaskCanceledException)) 
      throw; 
    } 
} 

điểm cần lưu ý; hủy bỏ là hợp tác xã. Bạn có thể sử dụng Token.WaitHandle để có được một xử lý và chờ đợi trên nó cùng với các xử lý (s) của nguyên thủy đồng bộ hóa khác. Mutex chậm hơn nhiều so với Monitor (hoặc khóa).

Thực sự nếu bạn không tin tưởng tác giả của mã đủ để họ thực hiện hủy hợp tác thì tôi sẽ đặt câu hỏi về tính bảo mật của việc chạy chúng bên trong AppDomain của bạn trên cùng một chuỗi.

Mọi chi tiết xem:

http://msdn.microsoft.com/en-us/library/dd997364.aspx

http://msdn.microsoft.com/en-us/library/dd537607.aspx

http://msdn.microsoft.com/en-us/library/ee191552.aspx

+0

Cảm ơn, đây là thông tin hữu ích. Tuy nhiên, tôi đã có ấn tượng rằng việc Task có thể lắng nghe yêu cầu hủy bỏ và tự mình ném ra OperationCancelledException nếu nó không thể hoàn thành đầy đủ. Tôi sẽ thử mã của bạn khi tôi có cơ hội chiều nay. –

+0

Từ liên kết đầu tiên, "Người nghe có thể được thông báo về yêu cầu hủy bỏ bằng cách bỏ phiếu, đăng ký gọi lại hoặc chờ xử lý chờ." Task.Wait hiệu quả khiến cho việc nghe xảy ra. –

+0

Xem: http://stackoverflow.com/questions/2293976/how-and-if-to-write-a-single-consumer-queue-using-the-task-parallel-library/2779208#2779208 ví dụ về sử dụng IsCancellationRequested để kiểm tra việc hủy và trả lời nó. –

-4

Bạn chỉ cần gọi Task.Wait(timespanToWait).

Nếu tác vụ không hoàn thành sau khoảng thời gian được chỉ định, nó sẽ bị hủy.

+0

Cảm ơn. Điều này hoàn toàn không rõ ràng từ tài liệu, nhưng nó có ý nghĩa khi bạn nghĩ về Nhiệm vụ như cách ly bạn khỏi bất kỳ chi tiết nào về cách các nhiệm vụ được lên lịch và quản lý. Bạn có biết nếu tôi sẽ phải làm bất cứ điều gì đặc biệt sau khi Wait trả về trước khi tôi có thể an toàn Vứt bỏ nhiệm vụ? –

+11

Đây không phải là câu trả lời. Wait() sẽ làm điều đó, chờ đợi. Nó sẽ không hủy bỏ/hủy bỏ nhiệm vụ. –

0

Dan Tôi không nghĩ Task.Wait (hết giờ) sẽ hủy tác vụ này, có quá tải Task.Wait (timeout, cancelationToken), nhưng chỉ ném OperationCanceledException trên task.Wait khi mã thông báo được báo hiệu.

Task.Wait chỉ chặn cho đến khi một trong hai tác vụ hoàn thành hoặc hết thời gian chờ, nó không hủy bỏ hoặc hủy bỏ nhiệm vụ chính nó. Vì vậy, nhiệm vụ bế tắc sẽ vẫn treo trong ThreadPool. Bạn không thể hủy bỏ tác vụ chưa hoàn thành (InvalidOperation).

Im writting cùng một loại ứng dụng như bạn và tôi đã viết TaskScheduler của riêng tôi mà cho phép hủy bỏ (và không được sử dụng threadpool :().

Nhưng im rất tò mò về cách bạn giải quyết vấn đề này. Xin trả lời

+0

Khi xem xét thêm, tôi quyết định rằng nếu một bế tắc có thể xảy ra, Thread.Abort thực sự chỉ che giấu bất kỳ vấn đề tiềm ẩn nào, vì trạng thái có thể đã bị hỏng. Như vậy, tôi đang xem xét một sự thất bại để chấm dứt để được gây tử vong (nhà điều hành có tùy chọn để tiếp tục chờ đợi hoặc chấm dứt ứng dụng). Điều này là đủ cho ứng dụng của tôi vì nó không phải là nhiệm vụ quan trọng; nếu ứng dụng là nhiệm vụ quan trọng, tôi sẽ phải di chuyển sang sử dụng AppDomains hoặc quy trình lưu trữ riêng cho mã được tin cậy một phần. –

+0

Dan, tôi nghĩ đây là cách chính xác để suy nghĩ về điều này. Thread.Abort chắc chắn không phải là một giải pháp. Nó có thể để ứng dụng của bạn ở trạng thái không xác định. –

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