【问题标题】:Async P/Invoke calls异步 P/Invoke 调用
【发布时间】:2011-05-02 08:52:44
【问题描述】:

我正在为机器人控制器开发一个包装库,主要依赖于 P/Invoke 调用。

但是,机器人的许多功能,例如归位或移动,需要相当长的时间,并且在运行时会执行线程锁。

所以我想知道如何以异步方式包装功能,这样调用就不会阻塞我的 UI 线程。到目前为止,我的想法是使用 Tasks,但我不确定这是不是正确的方法。

public Task<bool> HomeAsync(Axis axis, CancellationToken token)
{
    return Task.Factory.StartNew(() => Home(axis), token);
}

目前,关于 .NET 中异步模型的大多数 MSDN 文章,主要是基于已经具有异步功能的库(例如 File.BeginRead 等)。但我似乎找不到太多关于如何实际编写异步功能的信息。

【问题讨论】:

  • 你用的是什么接口?或者这是一个必须独立于特定接口构建的库?
  • 假设您的意思是 UI 界面,建立在它之上的应用程序是 WPF。但我更愿意在库级别处理它,因此 UI 团队不必过多担心线程。
  • 机器人界面通常不会以这种方式工作。您将完全失去对设备的控制,甚至无法中止寻的移动。归位命令通常只是开始归位移动,然后您会在完成时轮询或获取信号。在您承诺这样做之前,请检查界面中可用的内容。
  • 完成后我没有收到任何信号。它是 90 年代初期大学里的一件遗留设备。我对什么是必要的很有信心。
  • 我也有类似的问题。你的决赛是什么。实施。

标签: c#


【解决方案1】:

你试过async delegates吗?我相信没有比它更简单的了。

如果您的线程阻塞方法是void Home(Axis),您必须首先定义一个委托类型,即。 delegate void HomeDelegate(Axis ax),然后使用 HomeDelegate 新实例的BeginInvoke 方法指向 Home 方法的地址。

[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 属性结合使用)对于检查您的异步任务是否真的完成非常有用。你可能不希望你的机器人张开手臂并留下一个杯子,直到杯子放在桌子上,你知道的;-)

【讨论】:

  • 而且您甚至不再需要定义委托类型。只需使用Action&lt;Axis&gt;
  • 我相信任务并行库将所有这些都包装到了任务类中,不是吗?
【解决方案2】:

我的第一反应是,这不是你应该在图书馆里做的事情。主要原因是您实现此类系统的方式可能取决于您在库上构建的接口类型。

也就是说,您基本上有两种选择。首先是IAsyncResult。可以在http://ondotnet.com/pub/a/dotnet/2003/02/24/asyncdelegates.html 找到对此的详细描述。

第二个选项是创建带有回调事件的命令。用户创建一个命令类并在其上设置回调。然后,您将命令安排到 ThreadPool,并在命令执行后引发该事件。

.NET 框架的旧接口主要实现IAsyncResult 方法,而新接口倾向于实现事件回调方法。

【讨论】:

  • 并且在 ThreadPool 上排队一个项目不会阻塞 UI 线程?即使我有事件告诉操作何时完成,如果我需要将所有调用包装到线程中以避免 UI 阻塞,那也是毫无意义的。
  • 将它排队到ThreadPool 不会阻塞,不会。使用回调接口的全部原因是您可以将同步留给 UI 接口实现。您只需提供一种方法来向 UI 发出您已完成的信号,然后 UI 从那里获取它。另一个优点是回调是可选的,所以当 UI 不需要通知时,它只是不注册回调,只是触发并忘记。
  • 是的,但回调模型也是我的第一个建议。我认为人们不熟悉 TPL?
  • 我的问题是你为什么要使用 TPL? TPL 有一个不同的目的,即引入并行代码结构(ForEach 就是一个很好的例子)。您正在做的是异步操作,IAsyncResultThreadPool 方法更适合。
  • 除了 IAsyncResult 模型需要大量不必要的样板代码。 TPL 不仅适用于并行代码,还适用于异步操作。 Hejlsberg 甚至在昨天的 PDC 演讲中也证实了这一点。
【解决方案3】:

经过一番热烈的讨论,我认为这样的事情将是黄金的中间道路。

public void HomeAsync(Axis axis, Action<bool> callback)
{
    Task.Factory
        .StartNew(() => Home(axis))
        .ContinueWith(task => callback(task.Result));
}

我认为这是两全其美。

【讨论】:

    猜你喜欢
    • 2014-02-24
    • 2010-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多