0

我在使用 Windows 窗体应用程序的 C++/CLI 中遇到了一些令人沮丧的问题。

所以问题是我必须使用 WebClient istance 从网络服务器下载文件。通常我使用 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++。但它不起作用...

4

1 回答 1

2

你不能等待,这会导致死锁。在主线程空闲并重新进入调度程序循环之前,DownloadFileCompleted() 方法无法运行。但它不是空闲的,它卡在 WaitOne() 调用中。因此该方法无法运行,也无法设置 MRE。这反过来又导致 WaitOne() 永远无法完成。一个致命的拥抱,你的程序永远无法恢复。标准线程错误之一。

目前尚不清楚您为什么要等待,所发布的 WaitOne() 调用根本没有意义。您可以简单地删除它,一切正常。也许在您的实际程序中实际上有一些代码,您必须将该代码移动到 DownloadFileCompleted() 方法中。

显示 UI 的线程的一般编程规则适用于此。它永远不会休眠,也永远不会阻塞。这样做会使 UI 无响应并显着增加死锁的几率。UI 是事件驱动的,例如由用户移动鼠标或按键触发的事件。触发事件时运行的代码只能在线程不执行任何其他操作时运行。下载完成也作为事件发出信号。

于 2015-03-28T11:24:07.260 回答