汇编教程之多线程编程
2008-04-28 09:32:07 来源:WEB开发网本课中,我们将学习如何进行多线程编程。另外我们还将学习如何在不同的线程间进行通信。
理论:
前一课中,我们学习了进程,其中讲到每一个进程至少要有一个主线程。这个线程其实是进程执行的一条线索,除此主线程外您还可以给进程增加其它的线程,也即增加其它的执行线索,由此在某种程度上可以看成是给一个应用程序增加了多任务功能。当程序运行后,您可以根据各种条件挂起或运行这些线程,尤其在多CPU的环境中,这些线程是并发运行的。这些是在W32下才有的概念,在WIN16下并没有等同的概念。
在同一进程中运行不同的线程的好处是这些线程可以共享进程的资源,如全局变量、资源等。当然各个线程也可以有自己的私有栈用于保存私有数据。另外每个线程需要保存其运行上下文以便在线程切换时能够记住或恢复其上下文,当然这是由操作系统来完成的,对于用户是透明的。
我们大体上可以把线程分成两大类:
处理用户界面的线程:该类线程产生自己的窗口并负责处理相关的窗口消息。用户界面线程遵守WIN16下的互斥原则,即没一刻仅有一个用户界面线程使用USER和GDI库中的内核函数,也就是说当一个用户界面程序在进入GDI或USER中时,内核不允许重入。由此我们可以推论出WIN95的该部分内核的代码是遵守16位模式的。而WINOWS NT是纯的32位操作系统,所以不存在这个问题。
工作者线程:该类线程不用处理窗口界面,当然也就不用处理消息了。它一般都运行在后台干一些计算之类的粗,这大概也是把它叫做工作者线程的原因吧。
运用W32的多线程模式来编程,我们可以遵循某种策略:即让主线程仅来做用户界面的工作,而其它繁重的工作则交由工作者线程在后台完成。这就好比我们日常生活中的许多例子。譬如:政府管理者好比是用户界面线程,它负责听取民意,给职能部门分配工作,然后把工作成果汇报给公众。而具体的职能部门就是工作者线程,它负责完成下达的具体工作。如果让政府管理这来具体地做每一件事,它必须作一件事后再做另一项,那它就不能及时来听取和反馈民意。这样就无法管理好一个国家了。当然即使采用多线程制,政府管理部门也不一定就能管理好国家,但是程序却可以采用多线程机制来管理好她自己的工作。我们可以调用CreateThread函数来生成新线程。该函数的语法如下:
CreateThread proto lpThreadAttributes:DWORD,\
dwStackSize:DWORD,\
lpStartAddress:DWORD,\
lpParameter:DWORD,\
dwCreationFlags:DWORD,\
lpThreadId:DWORD
生成一个线程的函数和生成一个进程基本相同。
lpThreadAttributes -->如果您想要线程有缺省的安全属性,可以置该值为NULL。
dwStackSize --> 指定线程的堆栈大小。如果为0,那线程的大小和进程相同。
lpStartAddress--> 线程函数的起始地址。注意该函数仅接收一个32位的参数和返回一个32位的值。(该参数可以是一个指针,而且进程的线程可以直接存取进程定义全局变量,所以您大可不必担心不能如何把大量的参数传递给线程)。
lpParameter --> 传递给线程的上下文。
dwCreationFlags -->如果是0的话则表示创线程建后立即启动,相反的是标志位CREATE_SUSPENDED,这样您需要稍后显示地让该线程运行。
lpThreadId --> 内核给新生成的线程分配的线程ID。
如果生成线程成功的话,CreateThread函数就返回新线程的句柄。否则返回NULL。
如果没有给参数dwCreationFlags指定CREATE_SUSPENDED的话,该线程就会立即运行。如果不这样,我们上面说了,需要显示地启动该线程,要这样做您需要调用ResumeThread函数。
在线程返回后(线程的执行类似与执行一个函数,如果它调用了最后一条指令后,在汇编中是ret,那么该线程就结束了,除非您让它进入一个循环,譬如我们讲的用户界面线程就是如此,只不过它不退出的原因是进入的循环是在{while ( GetMessage(...))...}中,如果您没有给它传递一个值为0的消息,那它可不会退出),系统会自动调用ExitThread函数透明地处理线程一些退出时的清理工作。当然您可以自己调用该函数,但似乎没有什么意义。要得到退出时的退出码,您可以调用GetExitCodeThread函数。
更多精彩
赞助商链接