Я разрабатываю приложение 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
}
Править
Последовательность логических операций:
Проблема находится на 3-й точке, когда выполнение пятится к для цикла, я должен заблокировать цикл от продолжения, пока обратный вызов не называют.
Итак, если я правильно понимаю, вы хотите вызвать 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# методах блок по умолчанию, поэтому ничего делать не надо. Я предполагаю, что по какой-то причине вы вызываете неблокирующий метод, который запускает фоновую задачу / thread / что угодно и дает вам обратный вызов, когда он закончен. Вы хотите вызвать этот асинхронный метод синхронно.
Вы можете вызвать fun
изнутри обратного вызова. Что-то в этом направлении (псевдокод):
int n;
callFunTenTimes()
{
n = 0;
fun(n);
}
callback()
{
++n;
if (n < 10)
fun(n);
else
print("done");
}
Это похоже на стиль передачи продолжения .
Преимущество этого метода в том, что вы также можете сделать свой метод асинхронным без добавления дополнительных потоков, блокировок или дополнительной логики - вы просто предоставляете функцию обратного вызова, на которую может подписаться ваш клиент. Он хорошо работает в среде, управляемой событиями.
Zebrabox имеет право использовать WaitHandle. В то время как решение Джульетты действительно работает, поток, выполняющий spin-wait, будет потреблять значительное количество процессора пропорционально 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.