Проблема многопоточности с BeginInvoke, EndInvoke?

У меня есть клиентское приложение, которое отображает значения в реальном времени. Значения предоставляются через DDE-Advise. Эти значения в реальном времени представляют собой движущуюся ось станка с ЧПУ. Таким образом, через этот DdeClientAdviseметод поступает около 100 советов в минуту.
Когда приложение получает много DDE-советов, кажется, что внезапно все советы теряются.
Я уменьшил количество проблема в следующем:

public class NcddeZugriff
{
  private DdeClient _ddeClient; //see http://ndde.codeplex.com/

  public NcDdeZugriff()
  {
    _ddeClient = new DdeClient("ncdde", "machineswitch");
    _ddeClient.Connect();
    _ddeClient.Advise += DdeClientAdvise;
  }

  private delegate void CallbackDelegate(object sender, DdeAdviseEventArgs e);    

  private void DdeClientAdvise(object sender, DdeAdviseEventArgs e)
  {
    CallbackDelegate callbackDelegate = DdeClientAdviseCallback;
    _logging.InfoFormat("Advise-Callback for {0}", e.Item);
    //LINE A : return;

    callbackDelegate.BeginInvoke(sender, e, callbackDelegate.EndInvoke, null);
  }

  private void DdeClientAdviseCallback(object sender, DdeAdviseEventArgs e)
  {
    _logging.InfoFormat("Asynchron for {0}", e.Item);
    //do some work with e.Text...
  }
}

Если я удалю комментарий LINE A, все работает нормально, ни один совет не пропадет. Все советы регистрируются.
Если я включу BeginInvoke, через некоторое время DdeClientAdvise-Метод больше не будет вызываться, больше не будет записей в журнале.

Что я делаю неправильно с BeginInvoke, EndInvoke?

Изменить: добавить дополнительную информацию о классе.


person WaltiD    schedule 15.07.2011    source источник
comment
Чего вы пытаетесь достичь, ускорить обработку рекомендаций, вынеся логирование в отдельный поток?   -  person sll    schedule 15.07.2011
comment
Функция DdeClientAdvise находится поверх стека предоставленного кода. Кто вызывает функцию DdeClientAdvise?   -  person Tigran    schedule 15.07.2011
comment
Хороши шансы, что делегат получает сбор мусора с таким кодом. Невозможно понять, какой из фрагментов. Проверьте эту теорию, используя GC.Collect() для раннего запуска GC. Исправьте, сохранив экземпляр делегата в поле класса.   -  person Hans Passant    schedule 15.07.2011
comment
@Tigran: Класс DdeClient подписывается на DDE-сервер. Метод DdeClientAdvise является обратным вызовом для события Advise класса DdeClient.   -  person WaltiD    schedule 15.07.2011
comment
@sll: в отдельном потоке вызывается другой поток, в зависимости от e.item. Но в настоящее время это не имеет никакого влияния на проблему. Потому что сейчас код такой же, как и выше.   -  person WaltiD    schedule 15.07.2011
comment
@Hans Passant: Ты говоришь о CallbackDelegate? Поэтому я бы использовал такое поле, как private CallbackDelegate _callbackDelegate;. Но я хотел бы вызывать нового делегата для каждого совета DDE.   -  person WaltiD    schedule 15.07.2011


Ответы (2)


вам не нужно вызывать EndInvoke внутри DdeClientAdviseCallback?

person duedl0r    schedule 15.07.2011

Похоже, @Hans Passant был прав: делегат собирал мусор. Сохранение делегата в поле, кажется, решает проблему.
Хотя я изменил дизайн всего проекта. Поэтому я не могу точно сказать, что это решило проблему.

person WaltiD    schedule 08.09.2011