我在使用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#。我只是翻译了#34;从c#到c ++的解决方案。但它没有用......
答案 0 :(得分:2)
你不能等待,这会导致死锁。在主线程空闲并重新进入调度程序循环之前,DownloadFileCompleted()方法无法运行。但它不是空闲的,它停留在WaitOne()调用中。因此该方法无法运行且无法设置MRE。这反过来导致WaitOne()永远不会完成。一个致命的拥抱,你的程序永远无法恢复。标准线程错误之一。
目前尚不清楚为什么等待,根本没有发出WaitOne()调用的信号。你可以简单地删除它,一切正常。也许实际程序中有一些代码,你必须将该代码移到DownloadFileCompleted()方法中。
显示UI的线程的常规编程规则适用于此处。它永远不会睡觉,它永远不会阻止。这样做会使UI无响应并显着增加死锁的可能性。 UI是事件驱动的,由例如用户移动鼠标或按键触发的事件。触发事件时运行的代码只能在线程没有执行任何其他操作时运行。下载完成也会作为事件发出信号。