Подтвердить что ты не робот

С#: блокирование вызова функции до тех пор, пока не будет выполнено условие

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

Я получил простой цикл, который вызывает функцию "Загрузить"

 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);  

 }

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

Upload_Completed_callback()
{
  //Callback event
}

Изменить

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

  • Fun получает вызов (из цикла)
  • Логика удовольствия выполнена и выполнена.
  • Возврат к циклу
  • Обратный вызов будет вызван в конечном итоге, когда UploadFileAsync (который запускает некоторую логику в другом потоке) закончится

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

4b9b3361

Ответ 1

Итак, если я правильно понял, вы хотите вызвать UploadFileAsync, затем заблокировать, пока асинхронный вызов не ударит ваш обратный вызов. Если это так, я бы использовал AutoResetEvent i.e

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 означает, что состояние автоматически получает reset после того, как Set был вызван, а ожидающий поток получает сигнал через WaitOne

Ответ 2

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

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

int n;

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

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

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

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

Ответ 3

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

Ответ 4

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

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.