С#: блокирование вызова функции до тех пор, пока не будет выполнено условие
Я разрабатываю приложение С# 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.
Ответы
Ответ 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.