有一个decimal
参数。假设它等于 100
。有一个 Task
每 100ms
将它减少 0.1
。一旦参数变为等于 1
,任务就应该结束并且参数不应再减少。如果只有一个任务,工作没有问题。但是如果有2, 3, 100...
那么参数最终会变成小于1
。我尝试使用CancellationToken
结束所有任务,但结果还是一样。我的代码:
class Program
{
static decimal param = 100;
static CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
static CancellationToken token;
static void Main(string[] args)
{
int tasksCount = 16;
token = cancelTokenSource.Token;
Console.WriteLine("Start Param = {0}", param);
Console.WriteLine("Tasks Count = {0}", tasksCount);
var tasksList = new List<Task>();
for (var i = 0; i < tasksCount; i++)
{
Task task = new Task(Decrementation, token);
tasksList.Add(task);
}
tasksList.ForEach(x => x.Start());
Task.WaitAny(tasksList.ToArray());
Console.WriteLine("Result = {0}", param);
Console.Read();
}
private static void Decrementation()
{
while (true)
{
if (token.IsCancellationRequested)
{
break;
}
if (CanTakeMore())
{
Task.Delay(100);
param = param - 0.1m;
}
else
{
cancelTokenSource.Cancel();
return;
}
}
}
private static bool CanTakeMore()
{
if (param > 1)
{
return true;
}
else
{
return false;
}
}
}
输出不同,但总是小于1
。如何修复?
最佳答案
您的任务正在并行检查和修改相同的共享值,在某种程度上是您的 CPU 架构和/或操作系统所允许的。
任何数量的任务都可能“同时”遇到 CanTakeMore()
结果为 true
(当它们以共享值为 调用它时) 1.1m
),然后所有从该调用中收到 true 的人将继续减少共享值。
这个问题通常可以通过使用 lock
来避免。 声明:
private static object _lockObj = new object();
private static void Decrementation()
{
while (true)
{
if (token.IsCancellationRequested)
{
break;
}
lock (_lockObj)
{
if (CanTakeMore())
{
Task.Delay(100); // Note: this needs an `await`, but the method we're in is NOT `async`...!
param = param - 0.1m;
}
else
{
cancelTokenSource.Cancel();
return;
}
}
}
}
这是一个有效的 .NET Fiddle:https://dotnetfiddle.net/BA6tHX
关于c# - 如果至少有一个任务结束,如何关闭所有任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73367098/