2009-07-11 4 views
1

Я использую API, который изначально был написан с помощью собственного кода и завершен с помощью .net-операций. API работает asynchronic, когда каждая операция вызывает событие, когда оно завершено. Вся моя логика синхронизирована, поэтому я хочу синхронизировать операции. Я делаю это с EventWaitHandle. вот кодСинхронизация событий, основанных на одном объекте com

Stock stock; 

private System.Threading.EventWaitHandle _signal = null; 

public void Sync() 

{ 

     _signal = new System.Threading.EventWaitHandle(false,  
         System.Threading.EventResetMode.AutoReset); 
     MBTradingProvider.Instance.FinnishGetStoch += new 
         EventHandler(Instance_FinnishGetStoch); 
     MBTradingProvider.Instance.GetStockAsync("IBM"); 
     _signal.WaitOne(); 
} 

void Instance_FinnishGetStoch(object sender, EventArgs e) 

{ 

     stock = MBTradingProvider.Instance.CurrentWorkongStock; 
     if (_signal != null) 
      _signal.Set();   
} 

Этот код застрял в строке _signal.WaitOne(), текущий поток замерзает и ничего не будет случилось. Я работал с одним и тем же шаблоном на другой асинхронной операции, и я отлично работаю. Единственное отличие, о котором я могу думать, это то, что под капотом работают объекты com, поскольку я сказал, что эффект, который я получаю, состоит в том, что код не отвечает после строки WaitOne

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

ответ

0

Одной из проблем с этим кодом является назначение переменной _signal. Эта переменная атомизирована, но она не обязательно видна между всеми задействованными нитями. Вам необходимо использовать метод Interlocked.Exchange, чтобы гарантировать, что набор отображается одновременно во всех потоках.

System.Threading.EventWaitHandle temp = new System.Threading.EventWaitHandle(false,  
         System.Threading.EventResetMode.AutoReset); 
Interolocked.Exchange(ref _signal, temp); 

Кроме того, почему вы не используете событие AutoReset напрямую?

+0

Привет, я не получил решение. Насколько я понимаю, проблема может заключаться в том, что не все потоки видят мой EventWaitHandle (_signal). Я не понимаю, как этот код, использование локального «temp» EventWaitHandle, решает его? Можете ли вы объяснить это решение более подробно? Как я уже говорил, я использовал тот же код при вызове другой операции async, и он работает нормально. Может быть, есть разница в асинхронной структуре, которая используется в этих двух случаях? Спасибо. – 2009-07-11 22:39:08

0

Ваш код кажется мне в порядке.

Я предполагаю следующее:

  1. синхронизации() выполняется в ThreadA
  2. Вызов GetStockAsync() создаст ThreadB, который будет выполнять какую-то задачу, чтобы получить акции информацию
  3. По окончании получить акции Информация, ThreadB, не ThreadA, выполнит обработчик события, Instance_FinnishGetStoch(),

Моей грубая догадка что предположение №3 может быть неверным для вашей асинхронной структуры.

Возможно, вы захотите попробовать асинхронно и проверьте, какой поток выполняет GetStockAsyc(), и какой поток выполняет обработчик события Instance_FinishGetStock().

Если только один поток выполняет как GetStockAsync(), так и Instance_FinishGetStock(), ваш код, указанный выше, будет зависеть от _signal.WaitOne().

Например, в winform, если в потоке пользовательского интерфейса вызывается Form.BeginInoke (MyDelegate), MyDelegate будет выполняться в одном и том же потоке пользовательского интерфейса, но все же асинхронно.

+0

Привет, спасибо за ваш повтор. Я запускаю этот код в форме выигрыша, и когда я запускаю код асинхронно, он работает нормально. Я действительно не знаю, какой поток запускает мой асинхронный код, но поскольку я могу управлять своей формой во время работы async, я предполагаю, что он не использует поток пользовательского интерфейса. Я искал визуализатор или внешний инструмент для просмотра потоков, которые выполняются, но не смог найти их. Если вы можете порекомендовать его для меня, я буду рад. – 2009-07-11 22:21:22

+0

То, что я задаю, заключается в том, что обработчик события переводится обратно в поток пользовательского интерфейса или нет. Свойство Thread.CurrentThread.ManagedThreadId можно использовать для проверки идентификатора потока. Почему бы вам не открыть диалоговые окна, чтобы показать идентификатор id в потоке пользовательского интерфейса и в обработчике событий? В этом случае вы должны указать, выполняется ли обработчик события в потоке пользовательского интерфейса или нет. –

+0

Также вы можете установить контрольную точку в обработчике событий. Затем отладчик VS должен сообщить вам, какой поток запускает обработчик событий в потоках Windows в отладчике VS (Debug -> Windows -> Threads). –