解决多线程产生的“以前的函数求值超时,函数求值被禁用。必须继续执行才能重新启用函数求值”
Posted on 2008-12-13 16:54 Samson小天 阅读(10668) 评论(12) 编辑 收藏 举报今天下载漫画,结果VeryCD上有人只发布了Vol1和Vol2,后面就烂尾了。没办法,去在线看吧,要慢慢等网页加载好,还得看广告。所以就自己做了一个漫画下载者。
在多线程下载类中,我定义了一个DownloadFinished事件,并将下载信息都返回出去。但是主窗体接受到这个事件后什么都没执行,下了断点之后发现我传进来的参数都变成了“以前的函数求值超时,函数求值被禁用。必须继续执行才能重新启用函数求值”。
经过多方查证,终于发现了问题。大家先看我原来错误的代码:
传入的object实际上是包含着下载信息的一个DownLoadInfo类,我将里面的Uri提取出来,然后下载对应的文件。当下载完毕后发出DownloadFinished事件,事件传出去的第二个参数就是被下载的链接。但是当跨线程到主窗口(也就是主线程)后,这个传入的ui已经不能被访问了。这是为什么呢?
因为我是在辅助线程里得到的结果,也就是ui这个变量的可访问域只有这个副主线程而已。当DownloadFinished时间发出的时候,就代表着线程已经执行完毕,被销毁了。所以这线程上分配的变量当然都一股脑的被垃圾收集器列为回收对象,主线程自然就访问不到了。那怎么解决这个问题呢?看看下面的代码:
FileDownLoader是一个类,要想使用StartDownLoad启动线程下载,一定要先实例化一个FileDownLoader变量,而这个变量是存在于主线程的,这话隐含着_dInfo也是包含在主线程中的。再看看新的DownLoadImage方法。完成事件传入的参数不再是线程内的局部变量ui,而是在主线程中实例化好的DownLoadInfo类型的_dInfo变量。这样线程t被销毁时ui被销毁,但是在主函数中存在的_dInfo是不会被销毁的。这样就不会产生”以前的函数求值超时,函数求值被禁用。必须继续执行才能重新启用函数求值“的问题了。
本来想把漫画下载器放出来给大家下载的,但是这样对那个网站相当不利,毕竟人家也是要赚钱的。而且一旦放出来,人家肯定会出更BT的加密算法,我下次就要重新编写算法才能下载了。所以有需要的可以留言,我会把源代码发给大家,但是这里就不贴出来了。