C#:阻止函数调用直到满足条件

时间:2010-02-06 16:31:56

标签: c# winforms blocking

我正在开发一个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(在另一个线程中运行某些逻辑)结束时,将最终调用回调
  5. 问题出在第3点,当执行回到for循环时,我需要阻止循环继续,直到调用回调为止。

4 个答案:

答案 0 :(得分: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

接收到信号后,状态会自动重置

答案 1 :(得分:4)

默认情况下,在C#方法中阻止,所以你不需要做任何事情。我假设由于某种原因你正在调用一个非阻塞方法来启动一个后台任务/线程/其他什么,并在完成后给你一个回调。您希望以同步方式调用此异步方法。

您可以从回调中调用fun。沿着这些方向的东西(伪代码):

int n;

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

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

这类似于continuation passing style

此方法的一个优点是,您还可以使方法异步,而无需添加任何额外的线程,锁或额外的逻辑 - 您只需提供客户端可以订阅的回调函数。它在事件驱动的环境中运行良好。

答案 2 :(得分:3)

Zebrabox确实使用WaitHandle。 虽然Juliet的解决方案确实有效,但执行自旋等待的线程将占用与WaitHandle成比例的大量处理器,而WaitHandle实际上将处于空闲状态。

答案 3 :(得分: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类中获得进度指示器的好处。