Delphi 中多线程分析详解
2009-3-28 13:42:07 来源: 转载 4 次 字号:【大 中 小】 作者:James.Zhai 访问:3546 次 被顶:
核心提示: 多线程是多任务操作系统下一个重要的组成部分, 它能够提高应用程序的效率, 然而, 核心提示: 我们想利用好多线程,必须要了解很多的东西...
0. 前言 多 线程是多任务操作系统下一个重要的组成部分,它能够提高应用程序的效率,然而,我们想利用好 多线程,必须要了解很多的东西,比如操作系统的原理,堆栈概念 和使用方法。然而,使用不当,将会造 成无尽的痛苦。曾经刚刚接触的时候,我也为之恐惧,迷惑了好久。在无数次的失败和查找资料解决问题 之后,稍有感触,故写下此文,总结一下自己,同时,也给后学者一点启示,希望让他们少走弯路。
1.
基础知识。 基础知识。 线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有
一点在运行中必不可少的资源,但它可与同属一个进程的其它线程 共享进程所拥有的全部资源。一个线程 可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使 线程在运行中呈现出 间断性。线程也有就绪、阻塞和运行三种基本状态。 线程的生死。 windows 中,我们可以通过调用 API 在 CreateThread/CreateRemoteThread 创建一个
线程(其实,在 Windows 内部,CreateThread 最终是调用了 CreateRemoteThread 创建线程)。当线程 函数执行退出时,可以说这个线程已经完成了它的使命。调用 ExitThread 可以结束一个线程,同时调用 CloseHandle 来释放 Windows 分配给它的句柄资源。 GetExitCodeThread 可以用来检测线程是否已经退出。 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); 线程的控制。线程的有三种状态:就绪,阻塞,运行。当我们在 CreateThread 的时候,第 5 个参数 为 CREATE_SUSPENDED 标志时,线程创建后就处于挂起,即阻塞状态,否则,线程就会调用线程函数 立即执行。ResumeThread 可以让线程阻塞的线程继续运行,SuspendThread 可以让线程挂起。(具体用 法参考 MSDN) // SD,线程的属性 // initial stack size,线程堆栈的大小 // thread function,线程函数 // thread argument,参数 // creation option,创建时的标志 // thread identifier,线程的 ID
2. 线程同步 不同线程间公用同一个资源的时候,就需要进行线程同步。 为何要同步?要回答好这个问题我们要从栈说起。 这里说的栈, 和数据结构中的堆栈是不一样的。 (穿 插一个小的知识: 堆
和栈的区别。以前看过一个帖子,里面有个很精辟的回复,说明了堆和栈的区别: “堆就像自己在家里做饭,想做什么就做什么,但是,最后的锅碗等还需要自己去 收拾;而栈就像是去餐 馆吃饭,只要你点好菜,餐馆就给你提供,吃完之后锅碗什么的都不需要自己管。”,这说明堆和栈的区 别以及如何使用它们:堆,可以自己 完全控制,用完之后需要自己清理,处理不好就会造成内存泄漏;栈, 由操作系统分配,不需要进行管理,不用担心内存泄漏)。简单的说,栈就是一块内存区域, 它是从大到
小增长的, 它遵循后进先出的原则(FILO, First In Last Out)。 通常, CPU 的 EBP 和 ESP 是用作栈的, EBP 是栈的基地址,EBP 是当前栈顶的位置(栈顶永远是小于等于栈底的)。栈的主要作用就是保存现场,函 数参数传递。对于栈的操作汇编中有两条指令:PUSH 和 POP,分别用于数据入栈和出栈。这两条指令可 以影响 ESP 的值,当然你也可以直接使用 SUB ESP XXX、ADD ESP XXX 这种方式来更改栈顶的位置。 我们来看看函数