Асинхронный API для потоковой передачи данных с аппаратного устройства - PullRequest
7 голосов
/ 01 февраля 2012

Я пишу библиотеку на C #, но мне нужно сделать ее асинхронной.Обычно вы предоставляете набор функций DLL, и они принимают входные параметры и возвращают значение после завершения.Но как я могу сделать библиотечную функцию (вызываемую из C ++ / Delphi / Etc), которая уже начинает потоковую обратную передачу, все еще принимая ввод?

Единственное решение, которое я вижу сейчас, - это общение с использованием сокетов / pipe / etc,вместо вызовов DLL.

У кого-нибудь есть пример, как это сделать с обычными вызовами DLL?

Ответы [ 6 ]

1 голос
/ 01 февраля 2012

Одной хорошей моделью для прямого асинхронного вызова библиотеки (который находится в System.dll) является WebClient.DownloadStringAsync .Этот метод загружается из Uri асинхронно и вызывает событие DownloadStringCompleted каждый раз, когда оно завершается.

Ваша библиотека может также предоставить метод FooAsync, который не блокирует текущий потокно вызывает событие FooDataReceived всякий раз, когда некоторые данные поступают в вашу библиотеку, и событие FooCompleted, когда вычисление заканчивается.

0 голосов
/ 01 февраля 2012

Мне нравится следующий подход, потому что он делает его действительно простым для клиентов.

// 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
}

Суть в том, что вы запускаете метод в библиотеке, который сразу же возвращается, а затем уведомляет вызывающего по событию / делегату, что обработка завершена.Затем вы можете вызывать выполнение обратно в поток пользовательского интерфейса по мере необходимости.

Очевидно, обработка ошибок не включена в пример кода.

0 голосов
/ 01 февраля 2012

Согласно комментариям от OP, вызывающее приложение отправляет аудио в DLL, DLL отправляет аудио через некоторый интерфейс USB, DLL захватывает некоторое аудио с интерфейса микрофона и должно отправить захваченное аудио обратно в приложение, пока приложение отправляет аудио в DLL и т. д.

Исходя из этого и того факта, что вызов может быть написан на разных языках, я вижу некоторые варианты каналов связи:

  • TCP / IP (в зависимости от «настроек брандмауэра рабочего стола» и т. Д. Это может быть проблематично!)
  • Труба
  • COM-объекты с событиями / обработчиками событий
  • DLL с обратным вызовом, хотя это будет немного сложно для всех языков
  • совместно используемая память с глобальными мьютексами (может упростить это для потребляющего приложения, предлагая функцию «настройки» из DLL, которая возвращает указатели и имена мьютексов)
0 голосов
/ 01 февраля 2012
  • Поскольку вы хотите, чтобы и вход, и выход были асинхронными, вам понадобится рабочий поток: если ни входной поток, ни тот, который принимает выходные данные, не могут быть заблокированы, оба не могут быть обеспокоенывыполнить работу.

  • Вы уже думали об общении по каналам, но зачем использовать канал, а не внутреннюю структуру?

  • Итак, у вас естьэта очередь без блокировки на входе, другая на выходе и рабочий поток

  • Рабочий поток получает входные данные из очереди, обрабатывает их, помещает их в очередь

  • Если входная очередь становится пустой, рабочему потоку нечего перезаписывать, поэтому он вызывает событие «Need more data», а затем блокирует входную очередь, становясь (частично) полным

  • Если рабочий поток помещает что-то в очередь вывода, он вызывает событие «иметь больше данных», и если очередь вывода становится (полностью) заполненной, он блокирует доступное пространство вывода, становясь доступным

  • Ваш API неблокирует: ни отправка, ни получение вывода никогда не блокируют

  • Ваш API является асинхронным: уведомления (через события) выдаются

0 голосов
/ 01 февраля 2012

У Microsoft есть хорошая статья по этому вопросу. Если вы просто двигаете EndInvoke, он также должен работать для вас. http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.71).aspx

0 голосов
/ 01 февраля 2012

Есть несколько способов сделать это. В большинстве языков вы можете выполнять асинхронные вызовы методов, используя потоки или диспетчеры. В общем, до тех пор, пока ваш dll повторно входит (способный обслуживать несколько потоков одновременно), вызывающая среда может позаботиться об асинхронной части.

Тем не менее, можно запекать асинхронные вызовы в вашем API. Примером того, что делает это, являются клиентские прокси WCF .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...