我正在开发一个使用任务和信号量的概念验证应用程序来分解数字列表,目前我有一个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());
}
throw;
从Factor
中传播出去。这样可以传播取消操作。另外,考虑在一些地方使用await来简化逻辑。现在有些东西很难读懂。await特别适合自动切换回UI线程。 - usr