c# - 如果至少有一个任务结束,如何关闭所有任务

标签 c# .net async-await task

有一个decimal 参数。假设它等于 100。有一个 Task100ms 将它减少 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/

相关文章:

c# - 在 ASP.NET 2010 WebForms 中显示 .raw 图像

c# - 在 .NET 3.5 中使用 WCF DataContractJsonSerializer

javascript - 使用异步 Action Vuex 加载状态

c# - 使 AsyncLocal 更改传播到调用函数

c# - 在 C# 中尽可能快地在大列表中按位操作

C# 泛型不*不*实现某些东西

.net - 使用 .NET 的应用程序

javascript - 如何为 Promise 解析添加延迟?为 Node http.request Promise 添加延迟

c# - 我们总是需要使用 context.Server.MapPath 吗?如果我缓存结果怎么办?

c# - AppDomain.CurrentDomain.SetupInformation.PrivateBinPath 为空