简体   繁体   English

用于从硬件设备流式传输数据的异步API

[英]Asynchronous API for Streaming Data from a Hardware Device

I'm writing a library in C#, but I need to make it asynchronous. 我正在用C#编写一个库,但我需要使它异步。 Normally you expose a set of DLL functions, and they take input parameters, and return a value when finished. 通常,您公开一组DLL函数,它们接受输入参数,并在完成时返回一个值。 But how can I make a library function (callable from C++/Delphi/Etc) that already starts streaming back output while still taking input? 但是我怎样才能创建一个库函数(可以从C ++ / Delphi / Etc中调用),它在开始输入的同时已经开始流回输出?

The only solution I see now is to communicate using sockets/pipes/etc, instead of DLL calls. 我现在看到的唯一解决方案是使用套接字/管道/等进行通信,而不是DLL调用。

Does someone have an example how to do this with normal DLL calls? 有人有一个例子如何使用普通的DLL调用吗?

One good model for a straightforward asynchronous library call (which is located in System.dll ) is WebClient.DownloadStringAsync . 一个简单的异步库调用(位于System.dll )的一个好模型是WebClient.DownloadStringAsync This method downloads from a Uri asynchronously, and raises the DownloadStringCompleted event whenever it finishes. 此方法异步从Uri下载,并在完成时引发DownloadStringCompleted事件。

Your library could likewise provide a FooAsync method, which doesn't block the current thread but raises a FooDataReceived event whenever some data comes into your library and a FooCompleted event whenever the calculation finishes. 您的库同样可以提供FooAsync方法,该方法不会阻止当前线程,但只要有些数据进入您的库就会引发FooDataReceived事件,并在计算完成时FooCompleted事件。

There are a couple of ways to go with this. 有几种方法可以解决这个问题。 In most languages you can make async calls to methods using threads or dispatchers. 在大多数语言中,您可以使用线程或调度程序对方法进行异步调用。 In general, as long as you make your dll re-entrant (capable of servicing multiple threads at the same time) the calling environment can take care of the async part. 通常,只要您使dll 重新进入 (能够同时为多个线程提供服务),调用环境就可以处理异步部分。

It is possible to bake the async calls into your API, however. 但是,可以将异步调用烘焙到API中。 An example of something that does this is the WCF client proxies . 执行此操作的一个示例是WCF客户端代理

Microsoft has a good article on this matter. 微软在这件事上有一篇很好的文章。 If you just mover over the EndInvoke, it should work for you as well. 如果你只是在EndInvoke上移动它,它也应该适合你。 http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.71).aspx http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.71).aspx

  • Since you want both Input and Output to be async, you will need a worker thread: If neither the inputting thread, nor the one taking the output can be blocked, both can't be bothered to do the work. 由于您希望输入和输出都是异步的,因此您将需要一个工作线程:如果既不能阻止输入线程也不能阻止输出线程,那么两者都不会费心去做。

  • Your already thought of communicating via pipes, but why use a pipe and not an internal strcuture? 您已经考虑过通过管道进行通信,但为​​什么要使用管道而不是内部结构?

  • So you have this lock-free queue on the input, another one on the output and a worker thread 所以你在输入上有这个无锁队列,在输出上有另一个队列和一个工作线程

  • The worker thread takes input from the inqueue, processes it, puts it into the outqueue 工作线程从inqueue获取输入,处理它,将其放入出队

  • If the input queue becomes empty, the worker thread has nothing to crunch on, so he raises a "need more data" event and then blocks on the input queue becoming (partly) full 如果输入队列变空,那么工作线程没有什么可以处理,所以他引发了“需要更多数据”事件,然后在输入队列上阻塞变为(部分)满

  • If the worker thread puts something in the output queue, he raises a "have more data" event, and if the output queue becomes (fully) full, he blocks on output space becoming available 如果工作线程将某些内容放入输出队列,则会引发“有更多数据”事件,如果输出队列变为(完全)满,则会阻止输出空间变为可用

  • Your API is nonblocking: Neither sending input nor receiving output ever block 您的API是非阻塞的:发送输入和接收输出都没有阻塞

  • Your API is async: Notifications (via Events) are given 您的API是异步的:给出了通知(通过事件)

According to the comments from the OP the calling application sends audio to the DLL, the DLL sends audio out via some USB interface, the DLL captures some audio from the mic interface and needs to send the captured audio back to the application while the application sends audio to the DLL etc. 根据OP的评论,调用应用程序向DLL发送音频,DLL通过某些USB接口发送音频,DLL从麦克风接口捕获一些音频,需要在应用程序发送时将捕获的音频发送回应用程序音频到DLL等

Based on this and the fact that the calling can be written in rahter different languages I see some options for the communication channels: 基于此以及呼叫可以用不同语言编写的事实我看到了一些通信渠道的选项:

  • TCP/IP (depending on "desktop firewall settings" etc. this could be problematic!) TCP / IP(取决于“桌面防火墙设置”等,这可能会有问题!)
  • Pipes 管道
  • COM objects with events/event handlers 具有事件/事件处理程序的COM对象
  • DLL with callback although this will be a bit hard to get working for all languages 带有回调的DLL,虽然这对于所有语言来说都有点难度
  • shared memory with global mutexes (could ease that for the consuming application by offering a "setup" function from the DLL which return the pointers and mutex names) 共享内存与全局互斥(通过提供返回指针和互斥锁名称的DLL提供“设置”功能,可以简化消费应用程序的内存)

I like the following approach because it makes it really simple for the clients. 我喜欢以下方法,因为它使客户端非常简单。

// your library
class Foo {
   public event EventHandler ComputeCompleted = (sender, e) => { };

   public void Compute() {
      // kick off work on a background thread
      // possibly using the BackgroundWorker object
      var bw = new BackgroundWorker();      
      bw.RunWorkerCompleted += RunWorkerCompleted;
      bw.RunWorkerAsync(); 
   }

   private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
        ComputeCompleted(this, new object()); 
   }
}

// calling code
Foo foo = new Foo();
foo.ComputeCompleted += Completed;
foo.Compute();

private void Completed(object Sender, EventArgs e) {
   // process the result here
}

The gist is that you kick off a method in the library that returns right away, then notifies the caller via an event/delegate that the processing is complete. 要点是您启动库中立即返回的方法,然后通过事件/委托通知调用者处理完成。 You are then free to Invoke the execution back onto the UI thread as needed. 然后,您可以根据需要自由地将执行调用回UI线程。

Obviously, error handling not included in the sample code. 显然,错误处理不包含在示例代码中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM