首页 >后端开发 >C++ >AsyncOp 如何在多线程环境中有效管理任务排序和重入?

AsyncOp 如何在多线程环境中有效管理任务排序和重入?

Linda Hamilton
Linda Hamilton原创
2025-01-04 20:13:49278浏览

How Can AsyncOp Efficiently Manage Task Sequencing and Re-Entrancy in Multithreaded Environments?

任务排序和重入:在多线程环境中管理顺序命令

在实际的软件应用程序中,经常会遇到这样的情况其中任务按顺序处理,并且它们的执行顺序至关重要。当任务到达的速度比处理速度快时,任务排序变得更加复杂,并且它们是可重入的,这意味着它们可以在自身内部并发执行。

考虑以下场景:

  1. UI 命令处理程序任务可以同步或异步完成。
  2. 命令可以以比实际更快的速度到达已处理。
  3. 如果某个命令已存在待处理任务,则新的命令处理程序任务应排队并按顺序执行。
  4. 每个新任务的结果可能取决于前一个任务的结果

传统上,可以通过使用 Task.Factory.StartNew 方法和TaskScheduler.FromCurrentSynchronizationContext() 参数强制异步执行。但是,如果命令处理程序被设计为在内部同步执行,这种方法可能并不理想。

为了解决这一挑战,可以实现一个名为 AsyncOp 的自定义类。 AsyncOp 处理任务排序和重入要求。这是 AsyncOp 类的更新版本,具有附加功能:

class AsyncOp<T>
{
    private Task<T> _pending = Task.FromResult(default(T));
    private readonly object _lock = new object();

    public Task<T> CurrentTask => _pending;

    public Task<T> RunAsync(Func<Task<T>> handler, bool useSynchronizationContext = false)
    {
        Task<Task<T>> task = null;

        lock (_lock)
        {
            var pending = _pending;
            Task<T> wrapper = async () =>
            {
                // Await the previous task
                T prevResult = await pending;
                Console.WriteLine("\nPrevious task result: " + prevResult);

                // Start and await the handler
                return await handler();
            };

            task = new Task<Task<T>>(wrapper);
            var inner = task.Unwrap();
            _pending = inner;
        }

        task.RunSynchronously(useSynchronizationContext ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Current);

        return inner;
    }

    public async Task HandleCancelAsync()
    {
        Task pendingCopy = null;

        lock (_lock)
        {
            pendingCopy = _pending;
        }

        // Cancel previous tasks as long as they are not the latest (current) task
        if (pendingCopy != CurrentTask && pendingCopy != null) await ((Task)pendingCopy).ContinueWith(t => t.Dispose());
    }

    public async Task HandleRestartAsync()
    {
        Task pendingCopy = null;

        lock (_lock)
        {
            pendingCopy = _pending;
            if (pendingCopy.IsCompleted && pendingCopy != null) _pending = Task.FromResult(default(T));
        }
    }
}

此更新版本提供了以下增强功能:

  • 可重入性: AsyncOp 现在通过允许嵌套来支持重入
  • 线程安全: 锁用于保护 _pending 字段。
  • 取消/重新启动:HandleCancelAsyncHandleRestartAsync 方法允许您优雅地取消或重新启动任务序列。

使用此更新的 AsyncOp 类,可以重写问题中提供的示例代码如下:

using System;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var asyncOp = new AsyncOp<int>();

            Func<int, Task<int>> handleAsync = async (arg) =>
            {
                Console.WriteLine("This task arg: " + arg);

                // Delay the execution
                await Task.Delay(arg); 

                return await Task.FromResult(arg); 
            };

            Console.WriteLine("Test #1...");
            asyncOp.RunAsync(() => handleAsync(1000));
            asyncOp.RunAsync(() => handleAsync(900));
            asyncOp.RunAsync(() => handleAsync(800));
            await asyncOp.CurrentTask;

            Console.WriteLine("\nPress any key to continue to test #2...");
            Console.ReadLine();

            asyncOp.RunAsync(() =>
            {
                var handle100Task = handleAsync(100);
                asyncOp.RunAsync(() => handleAsync(200), true);
                return handle100Task;
            });

            await asyncOp.CurrentTask;
            Console.WriteLine("\nPress any key to exit...");
            Console.ReadKey();
        }
    }
}

在这个更新版本中,handleAsync任务被强制运行使用 Task.Delay 方法异步演示 AsyncOp 的重入功能。

该解决方案提供了一种强大且高效的方法来管理任务排序和重入,确保命令无论它们到达的速度如何,都按照所需的顺序执行。

以上是AsyncOp 如何在多线程环境中有效管理任务排序和重入?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn