12

我正在开发一个 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
}

编辑

逻辑顺序:

  1. Fun 被调用(来自循环)
  2. 有趣的逻辑被执行并完成..
  3. 回到for循环
  4. 当 UploadFileAsync (在另一个线程中运行一些逻辑)将结束时,最终将调用回调

问题出在第三点,当执行移回 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

在 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。虽然 Juliet 的解决方案确实有效,但执行自旋等待的线程将消耗与 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 回答