我在Windows窗体应用程序的C ++ / CLI中遇到一个小问题,但令人沮丧。
因此,问题是我必须使用WebClient实例从Web服务器下载文件。通常我使用DownloadFile而不是DownoadFileAsyn,但是如果我想显示一个进度条,显示下载文件的进度,则必须使用DownloadFileAsyn。那么,我如何等待下载过程完成呢?
代码是:
ref class Example{
private:
static System::Threading::ManualResetEvent^ mre = gcnew System::Threading::ManualResetEvent(false);
public:
void Download();
void DownloadFileCompleted(Object^ sender, System::ComponentModel::AsyncCompletedEventArgs^ e);
};
void Example::Download(){
WebClient^ request = gcnew WebClient;
request->Credentials = gcnew NetworkCredential("anonymous", "anonymous");
request->DownloadFileCompleted += gcnew System::ComponentModel::AsyncCompletedEventHandler(this,&FileCrypt::DownloadFileCompleted);
request->DownloadFileAsync(gcnew Uri("ftp://ftp...."+remote_path),remote_file,mre);
mre->WaitOne();
/*
BLOCK OF INSTRUCTIONS THAT I WANT TO RUN AFTER THE FILE DOWNLOAD IS COMPLETED
*/
}
void Example::DownloadFileCompleted(Object^ sender, System::ComponentModel::AsyncCompletedEventArgs^ e){
MessageBox::Show("COMPLETED");
mre->Set();
}
因此,下载完成后,程序会在mre-> WaitOne()指令之后停止运行,并且不会运行上面编写的指令块。
DownloadFileCompleted()不会执行,实际上甚至会显示消息框。
有任何想法吗?我已经为这个问题进行了搜索,很多人都遇到了,但是仅限于C#。而且我只是将解决方案从c#“翻译”为c ++。但这行不通...
最佳答案
您不能等待,这会导致死锁。在主线程空闲并重新进入分派器循环之前,DownloadFileCompleted()方法无法运行。但是它不是空闲的,它被卡在WaitOne()调用中。因此,该方法无法运行,并且无法设置MRE。这又导致WaitOne()无法完成。致命的拥抱,您的程序将永远无法恢复。标准线程错误之一。
目前尚不清楚为什么要等待,根本就没有指向发布的WaitOne()调用的意义。您只需删除它,一切都可以正常工作。也许在您的真实程序中实际上有一些代码,您必须将该代码移到DownloadFileCompleted()方法中。
显示UI的线程的一般编程规则在这里适用。它永远无法入睡,也永远无法阻挡。这样做会使UI无响应,并显着增加了死锁的几率。 UI是事件驱动的,由用户移动鼠标或按下键触发的事件。触发事件时运行的代码只能在线程没有执行任何其他操作时运行。下载完成也以事件形式发出信号。