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

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

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

 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. Fun получает вызов (из цикла)
  2. Fun логика выполняется и делается..
  3. возвращается к for loop
  4. обратный вызов будет вызван в конце концов, когда UploadFileAsync (который запускает некоторую логику в другом потоке) закончится

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

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


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

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

int n;

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

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

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

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


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


проблема:

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.