{
线程的核心应用(DoubleCat)
一,Delphi的高级应用到了后期一点都不比C++简单,他只能说是一种入门容易,上手容的开发
工具,到了后期高级应用,也同是很多概念上的东西,别说java在搞一大堆概念上的东西,其实
Delphi也一样.本部份就Delphi的线程抛开理论见本质进行讲解.
二,多线程主要应用于网络开发,游戏开发中,数据库中尽量少用(不是说不能用),因为在数据
库开发中,为了防止数据的死锁与写入混乱,关系型数据库都提供了数据库事务主要是用来处
理死锁与写入混乱这个问题的.
三,线程的优先级别属性分为7级以tpNormal(tp=Thread Priority线程优先的意思)为中心,
向上3级(tpHigher 1 tpHighest 2 tpTimeCritical(时间临界) 15)
向下3级(tpLower -1 tpLowest -2 tpIdle(空闲) -15),线程的优先级别主要用于,在同一事
件中,二个线程运行,优先级别高的先得到运行(优先获得进程分配的CPU运行时间片),优选级
别高的运行完后再运行优先级别底的.后台软件中请把线程的优先级别设成tpLower以免和前
软件抢CUP的运行时间片,使得前台软件出现停卡的现像.
四,线程是个虚拟类,(包含虚拟方法的类就叫虚拟类,包含抽象方法的类就叫抽象类,不要再
把这种概念搞的更复杂了!)所以使用线程时必须定义一个线程类的子类(子类与父类的关系
往往是子大父小,这个不可以理解错了)然后在子类中覆盖线程类中虚拟的Execute方法,要
在线程中完成的动作(功能)全部写在Execute里.再次说明类的派生与继承是个什么盖念,派
生与继承是同一个概念,同一回事,派生类(继承类)拥有基类(父类)的全部功能,可以在派生
类中新加功能,也可以不加.如果基类(父类)是个虚拟类抽象类,派生类必须实现基类中的虚
拟抽象方法.(虚拟抽向方法,就是只给出方法名称而不给出方法的具体实现!如果只是虚拟方
法,那的目的是为了给泒生去用同名覆盖,实现多态而已,前指示字为Public 对protected,后
指示字为override,虚拟方法在基类中必须实现,当然可以空实现,虚拟抽象方法必须不实现,
方法后指示字virtual;abstract是一个整体不可分隔,这个多用于接口类)
五,线程类有个Terminated属性 和 Terminate 方法,Terminated返回线程是否中断,
Terminate是中断线程. Terminated用于Execute方法内的循环体内检查线程是否被外部中断,
与Break合用如果中断那就退出Execute代码的执行.如(if Terminated then Break),
而Terminate由其它线程发出,无论是子线程还是基本线程(中断其它线程的执行),
FreeOnTerminated(终止)属性是设置线程中止时释放线程所占用的资源,它也是用于
Execute方法内部的(FreeOnTerminated := True),这个方法如果线程不会异常中断是不需要
写的,正带线程中止时,系统自动回收线程所占用的资源,只是在有可能会异常中止的的情况
下加上这一句.这一句本来就是默认的.
六,Execute内常用Synchronize(方法名),这里的方法名只能是线程泒生类中定义的方法.
也就是同步执行另一个方法(即把另一个方法叫过来运行).
七,创建线程类实例Create(createSuspended:Boolean)方法是个带叁的方法,表示创建一个
挂起的线程实例还是立即执行的实例.如果带叁数True,那么创建的实例就是挂起的.
那就要用线程实例的Resume去唤醒[riˈzju:m]为恢复的意思.
七,Sleep()过程是线程方法概念就是让线程暂停多少毫秒,在线程睡觉中,如果有其它线程
等待运行的话,过程会立刻安排CUP运行时间片过去执行.
八,注意:线程的Execute是个过程,无论是用CreateThread去创建线程还是自定义线程泒生类
去实现线程动作,都不要去使用有返回值的函数,不要指望线程动作完成后返回一个叁数值给
你,在线程中做不到.
九,关于临界区,临界区不光在线程的Execute代码区内应用,其它地方的代码区也能用,
它的作用是标识一段代码同一时间内只能由一个线程执行.
由EnterCriticalSection开始到LeaveCriticalSection结束,
临界变量一般为单元文件变量(一个单元内最大的全局变量,整个单元文件内都可以使用)
,临界变量的创建与消毁可以放在窗体的创建与消毁时完成,也可以在单元文件的初使化
与终止化时完成,一般而言,一个单元文件用一个临界变量就好了,当然用多个也行.线程的
同步这个概念是错误的,应该叫线程异步,如,二个线程同时叫打印机打印不同的文档,如果
不用线程异步,打印机就会随机一下打这个线程的内容,一下打印另一个线程的内容,
这样就乱套了,线程异步就是处理先让一个线程做完他它要做的事情,再让另一个线程开始
做事.如下是一个使用临界区的线程异步例子.
}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
var
CS : TRTLCriticalSection; //定义临界区
//TRTL意思为T=type类的前缀,RTL=RunTimeLibrary(运行时库)
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type theThread = class(TThread)//定义线程类
protected
procedure Execute;override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
ThreadOne : theThread;//申明线程类实例
ThreadTwo : theThread;
begin
Memo1.Clear;
ThreadOne := theThread.Create(False);//创建即时运行的线程实例
ThreadTwo := theThread.Create(False);
end;
{ theThread }
procedure theThread.Execute;//线程泒生类Execute的实现部份
var
i : Integer;
begin
inherited;
EnterCriticalSection(CS);//进入临界区
FreeOnTerminate := True;//这句可要可不要
for i := 0 to 10 do begin
Form1.Memo1.Lines.Append(IntToStr(i));
if Terminated then Break;//这句可要可不要
end;
LeaveCriticalSection(CS);//离开临界区
end;
{
如果不想用线程类方法做线程动作,只是想把一个方法让线程去运行,那就用API函数
CreateThread,这个API的叁数如下
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全属性特征一般为nil
DWORD dwStackSize, // 堆大小一般为0自动大小
LPTHREAD_START_ROUTINE lpStartAddress, //传入方法的地址(线程开始例程),
这个叁数必须给,也就是告诉创
建的线程去做什么.
LPVOID lpParameter, // 是否这个线程还可以建立新线程一般为nil或0
DWORD dwCreationFlags, // 创建线程的标识,一般为0自动标识
LPDWORD lpThreadId // 返回线程的ID,这个变量叁数必须给
);
线程方法不都是我自己定义的吗?为什么要用CreateThrad这个API去创建线程?如果代码全是
你自己写的那都无所谓,用不着它,当在团队中协同开发时,别人写了一个方法在DLL中,而且必须
去同步那个DLL方法时,你别无选择,只能用这个API的CreateThread方法去创建一个
立即执行的线程
}
procedure ShowHelloWord; //定义一个方法
begin
ShowMessage('Hello Word');
end;
procedure TForm1.Button2Click(Sender: TObject);
var
ThreadId : DWORD;//定义变量用于装创建线程后返回的ID
begin
CreateThread(nil,0,@ShowHelloWord,nil,0,ThreadId);//用API函数创建线程并执行
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// DeleteCriticalSection(CS);//窗体消毁时删除临界区
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//InitializeCriticalSection(CS);//窗体创建时创建临界区
end;
initialization
InitializeCriticalSection(CS);//单元文件初使化时创建临界区
finalization
DeleteCriticalSection(CS);//单元文件终止化时删除临界区
end.
{
随便说一个这个end.这是与单元文件头unit配对的,表示单元文件的代
码区结束,unit标识单元代码区开始.unit…end.标识编译器查找单元文
件代码区的范围,不可以把单码写在unit前面(除了注释外)
当然也不可以把代码写在end.后面(除了注释外),
这个作用与java的单元文件类作用是一样的.
关于互斥量与信号量,用法差不多,知道有这个概念就行,当delphi提供多种方
法时,一定要精通一种方法.
DoubleCat
}