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