Асинхронные Звонки Вопрос Новичка - PullRequest
2 голосов
/ 20 марта 2009

Я работаю над небольшим проектом, в котором мне нужно сделать два асинхронных вызова сразу за другим.

Мой код выглядит примерно так:

AsynchronousCall1();
AsynchronousCall2();

Проблема, с которой я сталкиваюсь, заключается в том, что оба вызова занимают от одной до двух секунд, и я никогда не знаю, какой из них закончится последним. То, что я ищу, это способ определить, кто финиширует последним. Если Call1 () заканчивается последним, я делаю одну вещь. Если Call2 () завершается последним, я делаю другое.

Ответы [ 4 ]

6 голосов
/ 20 марта 2009

Это простой пример использования lock, чтобы гарантировать, что только один поток может ввести кусок кода. Но это общий пример, который может или не может быть лучшим для вашего приложения. Добавьте некоторые детали в свой вопрос, чтобы помочь нам найти то, что вы ищете.

 void AsynchronousCall1()
 {
      // do some work
      Done("1");
 }

 void AsynchronousCall2()
 {
      // do some work
      Done("2");
 }

 readonly object _exclusiveAccess = new object();
 volatile bool _alreadyDone = false;
 void Done(string who)
 {
      lock (_exclusiveAccess)
      {
           if (_alreadyDone)
               return;

           _alreadyDone = true;
           Console.WriteLine(who + " was here first");
      }
  }
2 голосов
/ 20 марта 2009

Я полагаю, что существует метод, который является членом класса Thread для проверки определенного потока и определения его статуса. Другой вариант - использовать BackgroundWorker, так как это позволит вам разобрать, что происходит, когда этот поток завершится, создав отдельные методы.

Опция "thread-unsafe" будет использовать переменную класса, и в конце каждого потока, если он не заблокирован / уже имеет значение другого потока, не устанавливайте его. В противном случае установите его.

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

Это даст вам ответ о том, какая нить закончилась первой.

1 голос
/ 20 марта 2009

Вы можете сделать это с двумя ManualResetEvent объектами. Идея состоит в том, чтобы основной поток инициализировал оба как unsignaled, а затем вызывал асинхронные методы. Затем основной поток выполняет WaitAny для обоих объектов. Когда AsynchronousCall1 завершается, он сигнализирует об одном из объектов. Когда AsynchronousCall2 завершается, он сигнализирует другому. Вот код:

ManualResetEvent Event1 = new ManualResetEvent(false);
ManualResetEvent Event2 = new ManualResetEvent(false);

void SomeMethod()
{
    WaitHandle[] handles = {Event1, Event2};
    AsynchronousCall1();
    AsynchronousCall2();
    int index = WaitHandle.WaitAny(handles);
    // if index == 0, then Event1 was signaled.
    // if index == 1, then Event2 was signaled.
}

void AsyncProc1()
{
    // does its thing and then
    Event1.Signal();
}

void AsyncProc2()
{
    // does its thing and then
    Event2.Signal();
}

Здесь есть несколько предостережений. Если оба асинхронных метода заканчивают работу до вызова WaitAny, невозможно сказать, какой из них завершился первым. Кроме того, если оба метода завершаются очень близко друг к другу (т.е. вызов 1 завершается, то вызов 2 завершается до освобождения ожидания основного потока), невозможно сказать, какой из них завершился первым.

0 голосов
/ 20 марта 2009

Возможно, вы захотите проверить шаблон проектирования Blackboard: http://chat.carleton.ca/~narthorn/project/patterns/BlackboardPattern-display.html. Этот шаблон устанавливает общее хранилище данных, а затем позволяет агентам (которые ничего не знают друг о друге - в данном случае ваши асинхронные вызовы) сообщать их результаты в этом общем месте. Тогда «супервизор» вашей доски будет знать, какой вызов завершился первым, и сможет соответствующим образом направить вашу программу.

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