2010-08-06 48 views
11

Tôi có một nhiệm vụ khởi chạy một số nhiệm vụ con. (ví dụ: Tác vụ A tạo B, C, D, E, F). Tôi cũng tạo một System.Threading.Timer để thăm dò ý kiến ​​một cơ sở dữ liệu cứ sau 10 giây để kiểm tra xem mục đã lên lịch đã bị hủy bỏ theo yêu cầu chưa. Nếu có, nó đặt CancellationTokenSource để tác vụ biết hủy. Mỗi tiểu nhiệm vụ, trong trường hợp này B, C, D, E, F, sẽ hủy bỏ khi thích hợp (chúng được lặp đi lặp lại các tập tin và di chuyển chúng xung quanh).Khi nào cần vứt bỏ System.Threading.Task với nhiệm vụ con?

Kể từ Task cụ IDisposable, tôi muốn biết nếu nó là một ý tưởng tốt để gọi Task.WaitAll một lần nữa từ khối catch, để chờ cho hủy để tuyên truyền. Trong khi yêu cầu hủy sẽ được xử lý, các tiểu nhiệm vụ có thể ở giữa một vòng lặp và không thể hủy bỏ cho đến khi hoàn thành

Tuy nhiên, theo MSDN:

Luôn gọi Dispose trước khi bạn phát hành của bạn tham chiếu cuối cùng cho Tác vụ. Nếu không, các tài nguyên mà nó đang sử dụng sẽ không được giải phóng cho đến khi bộ thu gom rác gọi phương thức Finalize của đối tượng Task.

Tôi có nên gọi lại lần nữa trên mảng nhiệm vụ của mình để gọi đúng Dispose() trên mỗi tác vụ trong mảng không?

public class MyCancelObject 
{ 
    CancellationTokenSource Source { get;set;} 
    int DatabaseId { get;set;} 
} 

private void CheckTaskCancelled(object state) 
{ 
    MyCancelObject sourceToken = (MyCancelObject)state; 

    if (!sourceToken.CancelToken.IsCancellationRequested) 
    { 
    //Check database to see if cancelled -- if so, set to cancelled 
    sourceToken.CancelToken.Cancel(); 
    } 
} 

private void SomeFunc() 
{ 
    Task.StartNew(() => 
    { 
    MyCancelObject myCancelObject = new MyCancelObject(
     databaseId, 
     new CancellationTokenSource()); 
    System.Threading.Timer cancelTimer = new Timer(
     new TimerCallback(CheckIfTaskCancelled), 
     myCancelObject, 
     10000, 
     10000);   
    Task[] someTasks = new Task[someNumberOfTasks]; 

    for (int i = 0; i < someNumberOfTasks; i++) 
     someTasks[i] = Task.Factory.StartNew(
     () => 
     { 
      DoSomeWork(someObject, myCancelObject.CancelToken.Token); 
     }, 
     TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning, 
     myCancelObject.CancelToken.Token); 

    try 
    { 
     Task.WaitAll(someTasks, cts); 
    } 
    catch (AggregateException) 
    { 
     //Do stuff to handle 
    } 
    catch (OperationCanceledException) 
    { 
     //Should I call Task.WaitAll(someTasks) again?? 
     //I want to be able to dispose. 
    } 
    } 
} 
+0

Tôi đã kiểm tra một số mã và thấy rằng 'Task.WaitAll' có thể được gọi lại để đợi các tác vụ vẫn đang chạy. Sau đó, chúng có thể được xử lý. Tôi vẫn muốn biết nếu có những cách khác để xử lý này mặc dù. –

+2

Nó không chỉ chấp nhận được câu hỏi của riêng bạn, nhưng nó được khuyến khích. Vui lòng đăng câu trả lời và chấp nhận câu trả lời nếu bạn cảm thấy như bạn đã tìm ra. –

Trả lời

2

Tôi cảm thấy như tôi đã tìm ra điều này, nhưng bất kỳ ai muốn thêm bất kỳ thứ gì hữu ích đều được hoan nghênh.

Tôi chỉ đơn giản gọi là Task.WaitAll() một lần nữa từ khối catch để đợi cho các tác vụ khác hoàn thành. Sau khi tất cả đã hoàn thành, tôi có một khối cuối cùng làm sạch tất cả các nhiệm vụ trong mảng.

try 
{ 
Task.WaitAll(someTaskArray, cancelToken) 
} 
catch (OperationCanceledException) 
{ 
Task.WaitAll(someTaskArray); 
} 
finally 
{ 
for (int i = 0; i < someTaskArray.Length; i++) 
someTaskArray[i].Dispose(); 
} 
+0

Tôi cảm thấy tồi tệ hơn thế, để chờ đợi tôi phải: thử {Tasks.WaitAll (công việc); } bắt (OperationCanceledException) { thử {Tasks.WaitAll (tác vụ); } catch (AggregateException) {Tasks.WaitAll (tác vụ); } } Sau đó, vứt bỏ ... Không chắc chắn lý do, nhưng điều này có vẻ hiệu quả. – Tom

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