使用ManualResetEvent c ++ / cli等待DownloadFileAsync

时间:2015-03-28 10:49:34

标签: c++ .net command-line-interface manualresetevent downloadfileasync

我在使用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 ++的解决方案。但它没有用......

1 个答案:

答案 0 :(得分:2)

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

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

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