C#: Блокирование вызова функции до условия, которое соблюдают

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

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

 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-й точке, когда выполнение пятится к для цикла, я должен заблокировать цикл от продолжения, пока обратный вызов не называют.

12
задан Madi D. 6 February 2010 в 22:38
поделиться

4 ответа

Итак, если я правильно понимаю, вы хотите вызвать 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

20
ответ дан 2 December 2019 в 05:27
поделиться

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

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

int n;

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

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

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

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

4
ответ дан 2 December 2019 в 05:27
поделиться

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

3
ответ дан 2 December 2019 в 05:27
поделиться

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

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.

1
ответ дан 2 December 2019 в 05:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: