像信号量或锁等待但仍处理调度程序队列以防止死锁?

时间:2014-05-28 15:57:14

标签: c# wpf multithreading deadlock dispatcher

我有一个Authorizer对象,可以从多个并发工作线程访问。如果用户最近登录,则可以立即返回访问令牌。但是,它必须调度到UI线程,以便在用户需要再次登录时向用户显示登录浏览器窗口。当login方法等待用户登录时,其他工作线程可能会请求授权,并且需要阻止那些直到用户完成登录。但是,由于外部调用也可能涉及UI线程,阻止外部调用还会阻止登录过程的前进进度,因为UI线程在重新进入时被阻止。

我不能只使用锁(每个线程可重入),因为调度到UI线程(UI元素交互所需)会解除线程与正在执行的操作之间的关系(线程可能)改变执行单个"逻辑"操作的过程,与许多操作相比,所有操作都必须同时使用相同的UI线程。)

另一种查看我的问题的方法是,每当我从Authorizer调用Dispatcher.Invoke来运行UI线程时,我都有可能会出现错误"错误的"在UI线程循环到Authorizer登录进程所需的操作之前,调度程序运行(或已经运行)的操作。我无法让这些其他访问继续进行,直到登录完成,但我无法恢复我的UI线程,直到完成。

一个解决方案就是拥有"阻止"实际上在阻塞时运行调度程序队列。这样的东西已经存在吗?如果我必须从头开始编写它,在我等待的时候,请求框架运行其他调度程序任务的最佳方法是什么?我应该做什么" while(阻止){dispatcher.Invoke(()=> {/ 没有 /}); }"

1 个答案:

答案 0 :(得分:1)

您需要异步处理所有这些,而不是同步处理,就像在桌面UI编程中经常这样。

您的Authorizer不应该阻止,直到它可以计算结果并返回该结果,它应该返回Task<AuthorizationInformation>,这将允许调用者在结果准备好时得到通知。该方法的调用者可能在UI线程上,也可能不在UI线程上,需要为该任务添加一个延续,然后放弃其调用链(如果它是UI线程,则为消息循环),以便允许{ {1}}做它的事情,然后继续执行应用于任务的延续。

授权方法可能如下所示:

Authorizer

public class Authorizer { private static Lazy<Task<AuthorizationInformation>> tcsFactory; static Authorizer() { tcsFactory = new Lazy<Task<AuthorizationInformation>>( () => { var tcs = new TaskCompletionSource<AuthorizationInformation>(); Dispatcher dispatcher = GetDispatcher(); dispatcher.BeginInvoke(new Action(() => { var login = new LoginWindow(); login.ShowDialog(); var info = login.LoginInfo; if (info != null) tcs.TrySetResult(info); else tcs.TrySetException(new Exception("Failed to log in.")); })); return tcs.Task; }); } public static Task<AuthorizationInformation> Authorize() { return tcsFactory.Value; } private static Dispatcher GetDispatcher() { throw new NotImplementedException(); } } 类型对于线程安全非常有用“计算此值不超过一次,让每个请求它的人都得到该值,但是在至少有一个人询问之前不要开始计算它这让我们懒洋洋地等待开始计算价值,然后当我们准备开始计算它时,我们创建一个Lazy来生成一个任务,只要我们有值,我们就可以完成。然后我们可以异步请求在UI线程中完成一些工作,然后在完成时设置任务的结果。