C #: блокировка вызова функции, пока не выполнено условие - PullRequest
12 голосов
/ 06 февраля 2010

Я занимаюсь разработкой приложения C # Winforms, часть приложения будет загружать файлы на веб-сервер, используя AsyncUpload (используя его, из-за необходимости использовать обратный вызов porgress), В программе C #

у меня есть простой цикл for, который вызывает функцию Uploading

 for(int i=0;i < 10 ; i++)
{
  Uploadfun();
}

А веселье творит волшебство:

Uploadfun()
  { 
  // Logic comes here

   // webClient.UploadFileAsync runs a 2nd thread to perform upload .. 
   webClient.UploadFileAsync(uri, "PUT", fileNameOnHD);  

 }

И обратный вызов, который вызывается после завершения асинхронной загрузки

Upload_Completed_callback()
{
  //Callback event
}

Редактировать

Логическая последовательность:

  1. Веселье вызывается (из цикла)
  2. Забавная логика выполнена и выполнена ..
  3. Возвращается к циклу
  4. Обратный вызов будет вызван в конце концов, когда UploadFileAsync (который выполняет некоторую логику в другом потоке) завершится

Проблема в 3-й точке, когда выполнение возвращается к циклу for, мне нужно заблокировать продолжение цикла до тех пор, пока не будет вызван обратный вызов.

Ответы [ 4 ]

20 голосов
/ 06 февраля 2010

Так что, если я правильно понимаю, вы хотите позвонить UploadFileAsync, а затем блокировать, пока асинхронный вызов не достигнет вашего обратного вызова. Если это так, я бы использовал AutoResetEvent т.е.

private readonly AutoResetEvent _signal = new AutoResetEvent(false); 

fun()
  { 
  // Logic comes here

   // runs a 2nd thread to perform upload .. calling "callback()" when done
   webClient.UploadFileAsync(uri, "PUT", fileNameOnHD);  

   _signal.WaitOne();   // wait for the async call to complete and hit the callback     
 }



callback()
 {
   //Callback event
   _signal.Set(); // signal that the async upload completed
 }

Использование AutoResetEvent означает, что состояние автоматически сбрасывается после вызова Set и ожидающий поток получает сигнал через WaitOne

4 голосов
/ 06 февраля 2010

В C # методы блокируются по умолчанию, поэтому вам не нужно ничего делать. Я предполагаю, что по какой-то причине вы вызываете неблокирующий метод, который запускает фоновую задачу / поток / что угодно и дает вам обратный вызов, когда это будет сделано. Вы хотите вызвать этот асинхронный метод синхронно.

Вы можете позвонить fun изнутри обратного вызова. Что-то вроде этого (псевдокод):

int n;

callFunTenTimes()
{
    n = 0;
    fun(n);
}

callback()
{
    ++n;
    if (n < 10)
       fun(n);
    else
       print("done");
}

Это похоже на стиль передачи продолжения .

Преимущество этого метода в том, что вы также можете сделать свой метод асинхронным, не добавляя никаких дополнительных потоков, блокировок или дополнительной логики - вы просто предоставляете функцию обратного вызова, на которую может подписаться ваш клиент. Он хорошо работает в среде, управляемой событиями.

3 голосов
/ 06 февраля 2010

Zebrabox действительно правильно использует WaitHandle. В то время как решение Джульетты работает, поток, выполняющий ожидание вращения, будет потреблять значительное количество процессора пропорционально WaitHandle, который по существу будет простаивать.

1 голос
/ 06 февраля 2010

Проблема здесь:

for(int i=0;i < 10 ; i++)
{
  fun(); <-- if we block until this function finishes here, we stop the UI thread
}

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

volatile downloadComplete;

void DownloadUpdates()
{
    ThreadPool.QueueUserWorkItem(state =>
        for(int i = 0; i < 10; i++)
        {
            downloadComplete = false;
            webClient.UploadFileAsync(uri, "PUT", fileNameOnHD);
            while(!downloadComplete) { Thread.Sleep(1); }
        });
}

Upload_Completed_callback()
{
    downloadComplete = true;
}

Теперь вы можете блокировать выполнение цикла, не прерывая поток пользовательского интерфейса, и вы также получаете преимущество от индикаторов прогресса от класса webclient.

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