发信人: down2()
整理人: fishy(2000-03-30 10:46:28), 站内信件
|
有人问到VB编写多线程方面的问题,为共同进步同时也为回应版主 cobe 的 提议,所以把以前写的一篇文章在此发表,希望有帮助。
首先用VB的API察看器得到的CreateThread函数说明是错误的,应如下:
Declare Function CreateThread Lib "kernel32" _
(lpThreadAttributes As SE CURITY_ATTRIBUTES, _
ByVal dwStackSize As Long, _
ByVal lpStartAddress As Long, _
ByVal lpParameter As Long, _
ByVal dwCreationFlags As Long, _
lpThreadId As Long) As Long
或
Declare Function CreateThreadL Lib "kernel32" _
Alias "CreateThread" _
(ByVal lpThreadAttributes As Long, _
ByVal dwStackSize As Long,
ByVal lpStartAddress As Long, _
ByVal lpParameter As Long, _
ByVal dwCreationFlags As Long, _
lpThreadId As Long) As Long
我配合这一篇文章写过一个例子,在我的网站有,例子的 URL 为:
Http://go.163.com/~llf/studio/Thread2.rar
不过我还没有用过很多的线程,一般只创建一个子线程,而不同线程之间需 要同步,VB 中的很多控件和函数可能都不是线程安全的,就是不能有两个线程同 时使用,这就需要一些技巧来达到同一时刻只有一个线程使用某控件或函数,不 过我没有做过,所以不说。
以下是原文。
多线程与 VB
“协作式多任务”、“抢占式多任务”、“多进程”、“多线程”这些词真 可以算是如雷贯耳了,不过词是词,了解是了解,两回事。我曾经煞有介事的向 一个同学说明什么是“多进程”,什么是“多线程”,不多久就发现我的解释是 完全错了的,所以现在我要讲的是 β2 版,有什么错误敬请提出。:)
先说说“协作式多任务”和“抢占式多任务”。在 Windows 3.1 中,多任务 方式是“协作式多任务”,意思是说一个任务得到了 CPU 时间,除非它自己放弃 使用 CPU ,否则将完全霸占 CPU ,所以任务之间需要协作——使用一段时间的 CPU ,放弃使用,其它的任务也如此,才能保证系统的正常运行;而在 Window s 95 中使用的就是“抢占式多任务”了,它的总控制权在 Windows 手中,Wind ows 会轮流询问每一个任务是否需要使用 CPU ,需要使用的话就让它用,不过在 一定时间后,Windows 会剥夺当前任务的 CPU 使用权,把它排在询问队列的最后 ,再去询问下一个任务……。这种方式上的不同造成 95 和 3.1 性能上的不同: 3.1 中如果有一个任务死锁,则系统也同样死锁;95 中有一个任务死锁,系统仍 能正常运行。
再说说“多进程”和“多线程”。同一个程序的多个运行的副本就是“多进 程”了;在 Windows 95 中,一个进程只是一段放置程序的内存,只有线程才是 真正运行的任务,所以一个进程至少包含一个线程,事实上,系统为每一个进程 创建一个缺省线程,叫做主线程,主线程可以创建子线程,子线程仍然可以再创 建子线程,这就是“多线程”了。Windows 对待线程是一视同仁的都作为一个任 务看待的,并不对主线程有什么优惠,这和 OS/2 稍有不同:Windows 下一个进 程中只要有一个线程在运行就不终止,但在 OS/2 下主线程结束时会同时关闭所 有的子线程。有一个同事对 OS/2 的这种线程管理方式很赞赏,我却不以为然, 我以为让线程自然的结束会比强制结束好的多。
Windows 3.1 是没有“多线程”的概念的,因为没有意义,只有在“抢占式 多任务”的方式下,“多线程”才有其用武之地。
“多线程”的“Hello World”是文件复制。在进行一个大文件的复制时,虽 然复制窗体上有一个“取消”按钮,但如果不是多线程,就只有到了文件复制完 毕时程序才知道用户按了“取消”钮,典型的先斩后奏,非我所欲也。当然也不 是完全没有办法解决,在 VB 中是用“DoEvents”,C 中是用“PeekMessage”, 不过在“协作式多任务”中这实在是一个危险的办法——此函数不知道什么时候 返回,但是硬件不等人,所以也只是没有办法的办法,何况即使在“抢占式多任 务”,这样做的效率也是很低的。而用“多线程”,可以用一个线程执行“疯狂 拷贝”,一个线程监视按钮状态,在用户按下了“取消”按钮时,程序马上就可 以知道,并且马上“取消”了。
“多线程”的说明到此为止,以下我要说一说 VB 的多线程问题。
官方的文件说 VB 不支持多线程,这其实是说 VB 中的语句并不都是线程安 全的,但是哪些是线程安全的,他们不说,我们也不知道,只有靠实践,我还没 有实践,所以也不知道。但是这并不是说 VB 程序真的是“单线程”的程序,事 实上至少每一个 ActiveX 控件都是一个线程,所以如果大家对 ActiveX 控件没 有我这样的恶感,大可开发一个 ActiveX 控件实现安全的多线程程序。至于 VB 缺省的控件是否也是用多线程实现的,我还不知道,各位如有兴趣,可以测试一 下。
在我做的多线程的例子里曾说过 VB 提供的“CreateThread”函数的说明是 错误的,关键在“函数地址”那一项使用了缺省的“ByRef”,而实际应该是“B yVal”的。此函数第一个参数是指定新线程的属性,产生安全描述符用的,可以 传一个“NULL”过去,表示不在乎,我在我的例子里就是这样做的;第二个参数 指定新线程的栈大小,也可以传一个“0”过去,说明和主线程一样;第三个参数 是函数地址,用“AddressOf”得到;第四个是参数指针;第五个是创建标志,缺 省值是“NULL”,表示立即执行,可斟酌使用;最后一个是用来返回线程的线程 标识符。
新线程函数定义为“Function 线程函数(ByVal 参数 As Long) As Long”。 “CreateThread”函数的参数一般情况下用缺省值就可以了,但是如果想传递参 数到新线程,C 不用说,指针是它的长项,只是在 VB 中,虽然可以用“VarPtr ”函数取得变量地址,但是这个地址对于 VB 程序本身却几乎是无用的,就是“ 线程函数”中得到的那个“参数”几乎是无用的。我说几乎是无用的,就是说事 实上还是有用的。:) 如果有很多参数要传递,使用“CopyMemory”是可以实现的 ,不过,这绝对是一个危险函数,不到不得已不用也罢;但是如果只需要传递一 个小于 32 位的值,我们就可以大张旗鼓的用这个“参数”了——虽然系统说此 参数是指针,不过传入传出以及解释权都是由你控制,谁也不能阻止你将一个“ Long”按值传递给“线程函数”,甚至如果你希望传递的是一个“Single”,也 只需要修改“CreateThread”和“线程函数”的说明即可,不用我多说了吧!当 然,最简单的方法有时候最有效——用全局变量,没有限制,只是有些麻烦。:)
对 VB 来说,简单的多线程程序还需要用到“ExitThread”,一般还要用到 “SuspendThread”、“ResumeThread”,这几个函数相对简单的多,就不多说了 。不过如果是复杂的多线程,就要用到一些线程同步的 API 了,我还没有用到, 总不能空穴来风,所以也不说了。
-- 欢迎访问点睛工作室(http://llf.126.com)
※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.106.245.73]
|
|