我已经创建了重用线程的类。这个类有一个用于排队作业的公共方法。
public AwaitableJob<T> PrepareJob(Func<T> job)
{
lock (locker)
{
var aj = new AwaitableJob<T>(job);
taskQueue.Enqueue(aj);
System.Threading.Monitor.PulseAll(locker);
return aj;
}
}
AwaitableJob是自定义类,它应该提供awaiter对象。
public class AwaitableJob<T> : INotifyCompletion where T : class
{
public Func<T> Job { get; private set; }
public bool IsCompleted { get; private set; } = false;
private object result;
public AwaitableJob(Func<T> job)
{
this.Job = job;
}
public AwaitableJob<T> GetAwaiter()
{
return this;
}
public void Invoke()
{
result = Job.Invoke();
IsCompleted = true;
}
public object GetResult()
{
return result;
}
public void OnCompleted(Action continuation)
{
continuation.Invoke();
}
}
我试图以这种方式使用它
public async void Connect()
{
var atm = await Worker.PrepareJob(ConnectHelper) as PresentModel;
if (atm == null) return;
var vm = new SwitchingViewModel(atm);
vm.NavigateTo();
}
但是不是等待它总是继续执行,所以atm变量总是为空。当我在AwaitableJob中添加断点时,它表明在IsCompleted设置为true之前调用了GetResult。谁知道哪里可能有问题?谢谢你的帮助。
答案 0 :(得分:1)
问题在于:
public void OnCompleted(Action continuation)
{
continuation.Invoke();
}
OnCompleted
的目的是注册 时的回调,但是你现在正在调用 继续 。你应该这样做的唯一时间是线程竞争条件,其中某人检查IsCompleted
并获得false
,但状态更改之间并注册回调。除此之外,您应该做的是存储回调,并从实际将状态更改为已完成的代码中调用它(看起来像您的{{1} })),再次记住考虑切换时的线程安全性。
坦率地说,如果这听起来很复杂:请使用Invoke