12

私はC#Winformsアプリケーションを開発しています。アプリケーションの一部は、AsyncUploadを使用してWebサーバーにファイルをアップロードします(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. 楽しいロジックが実行され、完了します。
  3. for ループに戻る
  4. UploadFileAsync (別のスレッドでいくつかのロジックを実行している) が終了すると、最終的にコールバックが呼び出されます。

問題は 3 番目のポイントにあります。実行が for ループに戻ると、コールバックが呼び出されるまでループが継続するのをブロックする必要があります。

4

4 に答える 4

20

したがって、私が正しく理解している場合は、UploadFileAsync呼び出してから、非同期呼び出しがコールバックに到達するまでブロックする必要があります。もしそうなら、私はAutoResetEventie を使用します

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
 }

UsingAutoResetEventとは、 が呼び出された後に状態が自動的にリセットSetされ、待機中のスレッドがシグナルを受信することを意味します。WaitOne

于 2010-02-06T16:55:48.717 に答える
4

In C# メソッドはデフォルトでブロックされるため、何もする必要はありません。何らかの理由で、バックグラウンドタスク/スレッド/何でも開始し、完了時にコールバックを提供するノンブロッキングメソッドを呼び出していると想定しています。この非同期メソッドを同期的に呼び出す必要があります。

コールバック内から呼び出すことができfunます。これらの行に沿ったもの (疑似コード):

int n;

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

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

これは継続渡しスタイルに似ています。

このメソッドの利点は、追加のスレッド、ロック、または追加のロジックを追加せずにメソッドを非同期にすることもできることです。クライアントがサブスクライブできるコールバック関数を提供するだけです。イベント駆動型環境でうまく機能します。

于 2010-02-06T16:37:51.287 に答える
3

Zebrabox は、WaitHandle を使用して適切に処理します。ジュリエットのソリューションは機能しますが、スピン待機を実行するスレッドは、基本的にアイドル状態になる WaitHandle に比例して大量のプロセッサを消費します。

于 2010-02-06T20:45:56.520 に答える
1

問題はここにあります:

for(int i=0;i < 10 ; i++)
{
  fun(); <-- if we block until this function finishes here, we stop the UI thread
}

あなたがやっていることはシーケンシャルです。また、UI スレッドをブロックする余裕がない場合は、ループを UI スレッドから移動します。

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 クラスから進行状況インジケーターの利点も得られます。

于 2010-02-06T17:37:51.877 に答える