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
Nguồn
2010-05-06 06:43:16
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. –
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. –
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ó. –