2010-02-06 5 views
12

Я разрабатываю приложение C# Winforms, часть приложения будет загружать файлы на веб-сервер с помощью AsyncUpload (используя его из-за необходимости использования обратного вызова porgress). C# программы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. Fun вызывается (из цикла)
  2. Fun логика выполнена и сделано ..
  3. Возврат к циклу
  4. Обратный звонок будет называться eventuall y, когда UploadFileAsync (который запускает некоторую логику в другом потоке) закончится

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

+3

У вас есть доступ к реалистичной игре? Вероятно, вам следует рассмотреть возможность предоставления синхронного интерфейса, на котором реализован асинхронный API. –

+0

Как вы его описываете, ваш код кажется последовательным и однопоточным, что означает, что до тех пор, пока функция 'callback' не будет вызвана, цикл не будет продолжен. Пожалуйста, поправьте меня, если я ошибаюсь, давая более подробное объяснение. –

+0

@Madi: Тогда вы делаете это назад. Вы должны использовать синхронную версию 'UploadFile' в основе логики и использовать асинхронный API поверх нее, если вам это нужно. –

ответ

20

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

+0

при использовании Waitone() после uploadAsync, программа останавливается, и Callback не вызывается. –

+0

okie .. я исправил проблему с остановкой, называемую fun() в отдельном потоке, «очевидно», вызвав ее в основном потоке, вызвал проблему! @Juliet Kinda помог указать на проблему .. спасибо вам обоим =) –

4

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

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

int n; 

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

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

Это похоже на continuation passing style.

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

+0

Thats funny. Я думал о своей собственной проблеме в этих строках: наличие функции обратного вызова делает «мясо» того, что использовал цикл. По-видимому, это решение позволяет свести время ожидания до минимума. – Joe

+0

Мне нужна версия async, потому что она обеспечивает обратный вызов «прогресс», который является основным требованием. –

+0

@Madi D: Если требование состоит в том, что загрузка должна вести себя асинхронно, почему бы не сделать вашу функцию асинхронной функцией тоже с обратным вызовом? Можете ли вы подробнее объяснить, для чего вы это используете? Это приложение WinForms, ASP.NET и т. Д.? –

1

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

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; 
} 

Теперь вы можете блокировать выполнение цикла без остановки вашего UI нити, и вы также получаете выгоду от индикаторы прогресса из класса webclient.

+0

Не используйте для этого логическую переменную, компилятор может ее оптимизировать (что приведет к поведению, которое никогда не будет продолжаться, о чем упоминает OP). zebrabox показал правильный способ сделать это с ожидаемым объектом события. –

+1

@Ben: Я ценю ваши комментарии, но я думаю, что они вводят в заблуждение. Во-первых, компилятор не собирается оптимизировать bool, если он используется или назначается где-то (и, предположительно, это). Во-вторых, ожидание очереди на bool и resetEvents - это допустимые способы блокировки потока, оба являются «правильным способом сделать это», и не являются «неправильными», выбор одного или другого зависит от вкусов программиста. – Juliet

+0

Спасибо за очень полезный ответ, закончив комбинирование потоков с вашим решением с помощью решения resevent @ebboxbox, и теперь он работает. =) –

3

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

+0

+1 пролить свет на верхние ответы (мне) .. –

+0

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

Смежные вопросы