我正在为机器人控制器创建一个包装库,它主要依赖于P / Invoke调用。
但是,机器人的许多功能(例如归位或移动)需要相当长的时间,并且在运行时会进行线程锁定。
所以我想知道如何以异步方式包装功能,因此调用不会阻止我的UI线程。到目前为止我的想法是使用任务,但我不确定这是正确的方法。
public Task<bool> HomeAsync(Axis axis, CancellationToken token)
{
return Task.Factory.StartNew(() => Home(axis), token);
}
目前,大多数关于.NET中Async模型的MSDN文章主要是在已经具有异步功能的库(例如File.BeginRead等)上进行转发。但我似乎无法找到有关如何实际编写异步功能的更多信息。
答案 0 :(得分:5)
你有没有试过async delegates?我相信没有什么比它简单。
如果你的线程阻塞方法是void Home(Axis)
,你首先要定义一个委托类型,即。 delegate void HomeDelegate(Axis ax)
,然后使用指向Home方法地址的HomeDelegate新实例的BeginInvoke
方法。
[DllImport[...]] //PInvoke
void Home(Axis x);
delegate void HomeDelegate(Axis x);
void main()
{
HomeDelegate d = new HomeDelegate(Home);
IAsyncResult ia = d.BeginInvoke(axis, null, null);
[...]
d.EndInvoke(ia);
}
请记住,在某处使用EndInvoke(阻塞线程,直到方法最终结束,可能与IAsyncResult.Completed属性的轮询一起)对于检查您的异步任务是否真的已经完成非常有用。你可能不希望你的机器人打开它的手臂并留下一个玻璃杯,直到玻璃杯在桌子上方,你知道; - )
答案 1 :(得分:5)
经过一番讨论后,我觉得这样的事情将成为黄金的中途。
public void HomeAsync(Axis axis, Action<bool> callback)
{
Task.Factory
.StartNew(() => Home(axis))
.ContinueWith(task => callback(task.Result));
}
我认为这是两全其美的。
答案 2 :(得分:1)
我的第一反应是,这不是你应该在图书馆里做的事情。主要原因是您实现此类系统的方式可能取决于您在库上构建的接口类型。
那就是说,你基本上有两种选择。首先是IAsyncResult
。可以在http://ondotnet.com/pub/a/dotnet/2003/02/24/asyncdelegates.html找到对此的详细描述。
第二个选项是使用回调事件创建命令。用户创建一个命令类并在其上设置回调。然后,将命令安排到ThreadPool
,并在执行命令后,引发该事件。
.NET框架的旧接口主要实现了IAsyncResult
方法,其中较新的接口倾向于实现事件回调方法。