我在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是事件驱动的,由用户移动鼠标或按下键触发的事件。触发事件时运行的代码只能在线程没有执行任何其他操作时运行。下载完成也以事件形式发出信号。

10-07 22:17