vcl线程内Synchronize更新主线程ui的问题

问题是这样的:我的Form会触发一个相当耗时的work,而同时我又不希望这个Form在做这个work的时候UI停止响应,所以,我把这个work放到了线程里执行(起了个继承自TThread的TWorker类),现在的问题时我想让这个工作的当前完成度在Form上以进度条的形式反馈给用户,也就是在线程中更新vcl组件的问题,


很显然生成新thread类时的模板中的注释提到过,要更新vcl组件需要使用Synchronize的方式调用更新vcl组件的方式,这样可以避免线程同步的问题,但是,我对这个worker线程的设计是,Form可以同时创建n个worker线程(做的work可能不相同),但是同一时间内只有一个工作线程能得到执行,这是因为我的几种工作中有一些是要依赖于其它工作的结果的,这一点我是通过TCriticalSection来保证的。在这个前提条件下,我以为不会有vcl组件更新的线程同步问题,所以开始的时候就没用Synchronize,经过试验,这样不Synchronize而直接操作Form的进度条组件时在有可能会出现 canvas does not allow drawing的异常,google了一些资料后我猜想这种错误可能是由于线程短时间内多次更新了form的ui组件,而由于前几次的更新重绘组件还没有结束导致的,也就是说线程没有得到form组件重绘结束的通知就发起了下一次重绘,这应该也算是一种线程同步的问题吧,于是,我开始改用Synchronize方法,把需要更新的UI比如progress bar的位置,status bar的提示文字等作为worker类的成员变量,以此来解决Synchronize调用的函数不能有参数的问题,其中progress bar的位置参数是double,status bar的文字是AnsiString,试验后又发现了新问题,在复制AnsiString的时候程序报了access violation异常,凭直觉简单分析后得出结论,Synchronize的工作方式是将提供的函数交给主线程(也就是有窗口函数的线程)执行,从而解决刚开始的那种问题,而这样的话,我那样复制就相当于是2个线程之间的内存访问,之所以double等赋值时没有出现问题,我想是因为其是通过寄存器直接传值的,而AnsiString的赋值实际上是传递了字符串变量的地址,也就是说,主线程要访问worker线程内存空间下的东西,所以出现了av异常,于是我把那几个成员变量改成了static(因为我有同一时间只有一个worker在工作的前提,所以这样不会搞乱),最后问题解决,俺的直觉没有错!

博主友情提示:

如在您的评论中需要提及如QQ号、微信号、电子邮件地址或其他隐私敏感信息,欢迎通过>>博主专用加密工具v2<<加密后发布,原文只有博主可以看到。