我正在開發一個概念驗證應用程序,該應用程序使用任務和信號量對數字列表進行分解,目前我有一個任務列表List<Task>
,需要FactorNumberClass
,然後計算目前FactorNumberClass
內特定數字的因子正常工作。對於每個任務T,我有一個ContinueWith
任務,用於更新總分數的進度,分解的平均時間,以及更新進度條的值(數字成功分解)/(需要分解的總數)。在將這些因子分解爲Tasks
時,輸入SemaphoreSlim.Wait(cancelToken)
將當前因子限制爲5個有效Tasks
。最後,我有一個ContinueWhenAll
,當所有任務完成時記錄。假設沒有取消,這一切都按我的意圖運作。檢測父級任務取消的正確方法是什麼?
當我嘗試取消任務時,出現問題,我無法檢測到任務是否已被取消,因此無法準確確定該號碼是否已成功分解或取消。如何檢測父任務是否被取消或運行完成?
取消標記定義:
public static CancellationTokenSource tokenSource = new CancellationTokenSource();
public static CancellationToken ct = tokenSource.Token;
因子類代碼:
public class FactorNumberClass
{
public FactorNumberClass()
{
}
public FactorNumberClass(int num, int threadnum)
{
this.number = num;
this.threadNumber = threadnum;
}
public List<int> factors = new List<int>();
public int number;
public int max;
public int threadNumber;
}
保理方法:
public void Factor(FactorNumberClass F, CancellationToken token)
{
LogtoStatusText("Thread: " + F.threadNumber + " Trying to enter semaphore");
try
{
ASemaphore.Wait(ct);
F.max = (int)Math.Sqrt(F.number); //round down
for (int factor = 1; factor <= F.max; ++factor)
{ //test from 1 to the square root, or the int below it, inclusive.
if (F.number % factor == 0)
{
F.factors.Add(factor);
if (factor != F.number/factor)
{
F.factors.Add(F.number/factor);
}
}
}
F.factors.Sort();
Thread.Sleep(F.number * 300);
LogtoStatusText("Task: " + F.threadNumber + " Completed - Factors: " + string.Join(",", F.factors.ToArray()));
LogtoStatusText("Thread: " + F.threadNumber + " Releases semaphore with previous count: " + ASemaphore.Release());
}
catch (OperationCanceledException ex)
{
LogtoStatusText("Thread: " + F.threadNumber + " Cancelled.");
}
finally
{
}
}
方法開始處理:
public void btnStart_Click(object sender, RoutedEventArgs e)
{
Task T;
List<Task> TaskList = new List<Task>();
LogtoStatusText("**** Begin creating tasks *****");
s1.Start();
AProject.FactorClassList.ForEach((f) =>
{
T = new Task(((x) => { OnUIThread(() => { RunningTasks++; }); Factor(f, ct); }), ct);
T.ContinueWith((y) =>
{
if (y.IsCompleted)
{
AProject.TotalProcessedAccounts++;
AProject.AverageProcessTime = (((Double)AProject.TotalProcessedAccounts/s1.ElapsedMilliseconds) * 1000);
}
OnUIThread(() => { RunningTasks--; });
OnUIThread(() => { UpdateCounts(AProject); });
});
TaskList.Add(T);
});
try
{
Task.Factory.ContinueWhenAll(TaskList.ToArray(), (z) => { LogtoStatusText("**** Completed all Tasks *****"); OnUIThread(() => { UpdateCounts(AProject); }); });
}
catch (AggregateException a)
{
// For demonstration purposes, show the OCE message.
foreach (var v in a.InnerExceptions)
LogtoStatusText("msg: " + v.Message);
}
LogtoStatusText("**** All tasks have been initialized, begin processing *****");
TaskList.ForEach(t => t.Start());
}
良好的漁獲物中,LogtoStatusText只是查看究竟發生了什麼事與一個輸出pp,但你完全正確 – Pseudonym
另外,如果取消已被請求,我不希望現有的等待任務進入信號燈,他們將如果我不使用等待(cancellationToken) – Pseudonym
我意識到這個答案可能實際上並沒有幫助你解決了這個問題。考慮使用'throw;'使得取消異常從'Factor'中冒出來。這種方式消除傳播。另外,考慮在幾個地方使用await來簡化邏輯。有些東西現在被聽到要閱讀。等待自動轉換回UI線程特別有用。 – usr