跨线程同步异步任务

时间:2018-01-31 05:04:54

标签: c# multithreading asynchronous

试图找出构建此问题解决方案的最佳方法

处理身份验证中间件时的HTTP请求管道。在JwtBearerOptions中运行OnTokenValidated与我的请求代码并行执行。我可以同步运行,但我不愿意,

我的部分要求要求此声明,我如何确保已设置此声明?

  1. 我正在并行运行两个线程,
  2. 一个异步函数依赖于另一个线程来设置变量
  3. 我创建了一个等待经理来完成我的任务。
  4. 但是,await manager有可能没有为任务设置密钥,因为我没有执行。
  5. 我的代码:

    public class TaskManager : ITaskManager
    {
    
        Dictionary<string, Task> _taskAwaiterMap = new Dictionary<string, Task>();
        public Task GetTaskForKey(string key)
        {
            this._taskAwaiterMap.TryGetValue(key, out var awaiter);
            return awaiter;
        }
    
        public void QueueTask(string key, Task task)
        {
            this._taskAwaiterMap[key] = task;
        }
    }
    

    修改

    public async Task GetManditoryTaskForKey(string key, int timeout)
    {
        var cancellationTokenSource = new CancellationTokenSource(timeout);
        await GetManditoryResolverWaitTask(key, cancellationTokenSource.Token);
    }
    
    protected async Task<Task> GetManditoryResolverWaitTask(string key, CancellationToken cancellationToken)
    {
        while (false == this._taskAwaiterMap.TryGetValue(key, out var task))
        {
            if(cancellationToken.IsCancellationRequested)
            {
                return Task.FromCanceled(cancellationToken);
            }
            await Task.Yield();
        }
    
        return this.GetTaskForKey(key);
    }
    

    我找到了一种等待设置密钥的方法,但这是同步异步任务的有效方法吗?

    修改

    在我的Http Pipe Line中,我会像这样排队任务:

    OnTokenValidated = async tvc => { await AuthenticationRule.ValidateToken(tvc); }
    
    //... Source ValidateToken
    //Some Potentially long Task
    var awaitManager = serviceProvider.GetRequiredService<ITaskManager>();
    var userClaimsTask = SetUserClaims(claimsIdentity, context, userSubjectId);    
    awaitManager.QueueTask(USER_CLAIM_AWAITER_KEY, userClaimsTask);
    

    如何有效地同步我的异步任务?

1 个答案:

答案 0 :(得分:2)

我试图回答你之前提出的问题。 :)

无论如何,我不确定这是解决问题的最佳方法,因为我不熟悉Async HTTP管道。但以下可以解决您正在采取的方法:

public class TaskManager : ITaskManager
{
    private readonly ConcurrentDictionary<string, TaskCompletionSource<Task>> _taskAwaiterMap = new ConcurrentDictionary<string, TaskCompletionSource<Task>>();

    public async Task GetTaskForKey(string key)
    {
        await await this._taskAwaiterMap.GetOrAdd(key, _ => new TaskCompletionSource<Task>()).Task;
    }

    public void QueueTask(string key, Task task)
    {
        this._taskAwaiterMap.GetOrAdd(key, _ => new TaskCompletionSource<Task>()).SetResult(task);
    }
}

我认为TaskManager只会在会话中存在。否则,您将不得不考虑如何清理_taskAwaiterMap