delphi多线程编程2

delphi多线程编程2

ID:15330090

大小:228.00 KB

页数:15页

时间:2018-08-02

上传者:U-3743
delphi多线程编程2_第1页
delphi多线程编程2_第2页
delphi多线程编程2_第3页
delphi多线程编程2_第4页
delphi多线程编程2_第5页
资源描述:

《delphi多线程编程2》由会员上传分享,免费在线阅读,更多相关内容在行业资料-天天文库

delphi多线程编程2在这段程序中,有三个线程几乎是同时建立,向窗体中的ListBox1中写数据,最后写出的结果是这样的:    能不能让它们别打架,一个完了另一个再来?这就要用到多线程的同步技术.  前面说过,最简单的同步手段就是"临界区".  先说这个"同步"(Synchronize),首先这个名字起的不好,我们好像需要的是"异步";其实异步也不准确...  管它叫什么名字呢,它的目的就是保证不**、有次序、都发生.  "临界区"(CriticalSection):当把一段代码放入一个临界区,线程执行到临界区时就独占了,让其他也要执行此代码的线程先等等;这和前面用的Lock和UnLock差不多;使用格式如下:varCS:TRTLCriticalSection; {声明一个TRTLCriticalSection结构类型变量;它应该是全局的}InitializeCriticalSection(CS);{初始化}EnterCriticalSection(CS);   {开始:轮到我了其他线程走开}LeaveCriticalSection(CS);   {结束:其他线程可以来了}DeleteCriticalSection(CS);  {删除:注意不能过早删除}//也可用TryEnterCriticalSection替代EnterCriticalSection.  用上临界区,重写上面的代码,运行效果图:    代码文件:unitUnit1;interfaceuses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls, Forms, Dialogs,StdCtrls;type TForm1=class(TForm)  ListBox1:TListBox;  Button1:TButton;  procedureFormCreate(Sender:TObject);  procedureFormDestroy(Sender:TObject);  procedureButton1Click(Sender:TObject); end;var Form1:TForm1;implementation{$R*.dfm}var CS:TRTLCriticalSection;functionMyThreadFun(p:Pointer):DWORD;stdcall;var i:Integer;begin EnterCriticalSection(CS); fori:=0to99doForm1.ListBox1.Items.Add(IntToStr(i)); LeaveCriticalSection(CS); Result:=0;end;procedureTForm1.Button1Click(Sender:TObject);var ID:DWORD;begin CreateThread(nil,0,@MyThreadFun,nil,0,ID); CreateThread(nil,0,@MyThreadFun,nil,0,ID); CreateThread(nil,0,@MyThreadFun,nil,0,ID);end;procedureTForm1.FormCreate(Sender:TObject);begin ListBox1.Align:=alLeft; InitializeCriticalSection(CS);end;procedureTForm1.FormDestroy(Sender:TObject);begin DeleteCriticalSection(CS);end;end. Delphi在SyncObjs单元给封装了一个TCriticalSection类,用法差不多,代码如下:unitUnit1;interfaceuses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms, Dialogs,StdCtrls;type TForm1=class(TForm)  ListBox1:TListBox;  Button1:TButton;  procedureFormCreate(Sender:TObject);  procedureFormDestroy(Sender:TObject);  procedureButton1Click(Sender:TObject); end;var Form1:TForm1;implementation{$R*.dfm}usesSyncObjs;var CS:TCriticalSection;functionMyThreadFun(p:Pointer):DWORD;stdcall;var i:Integer;begin CS.Enter; fori:=0to99doForm1.ListBox1.Items.Add(IntToStr(i)); CS.Leave; Result:=0;end;procedureTForm1.Button1Click(Sender:TObject);var ID:DWORD;begin CreateThread(nil,0,@MyThreadFun,nil,0,ID); CreateThread(nil,0,@MyThreadFun,nil,0,ID); CreateThread(nil,0,@MyThreadFun,nil,0,ID);end;procedureTForm1.FormCreate(Sender:TObject);begin ListBox1.Align:=alLeft; CS:= TCriticalSection.Create;end;procedureTForm1.FormDestroy(Sender:TObject);begin CS.Free;end;end.多线程编程(9)-认识等待函数WaitForSingleObject。                             一下子跳到等待函数WaitForSingleObject,是因为下面的Mutex、Semaphore、Event、WaitableTimer等同步手段都要使用这个函数;不过等待函数可不止WaitForSingleObject它一个,但它最简单.functionWaitForSingleObject( hHandle:THandle;   {要等待的对象句柄} dwMilliseconds:DWORD {等待的时间,单位是毫秒}):DWORD;stdcall;   {返回值如下:}WAIT_OBJECT_0 {等着了,本例中是:等的那个进程终于结束了}WAIT_TIMEOUT {等过了点(你指定的时间),也没等着}WAIT_ABANDONED{好不容易等着了,但人家还是不让咱执行;这一般是互斥对象}//WaitForSingleObject的第二个参数一般给常数值INFINITE,表示一直等下去,死等.  WaitForSingleObject等待什么?在多线程里就是等待另一个线程的结束,快来执行自己的代码;不过它可以等待的对象可不止线程;这里先来一个等待另一个进程结束的例子,运行效果图:    代码文件:unitUnit1;interfaceuses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms, Dialogs,StdCtrls;type TForm1=class(TForm)  Button1:TButton;  procedureButton1Click(Sender: TObject); end;var Form1:TForm1;implementation{$R*.dfm}var hProcess:THandle;{进程句柄}{等待一个指定句柄的进程什么时候结束}functionMyThreadFun(p:Pointer):DWORD;stdcall;begin ifWaitForSingleObject(hProcess,INFINITE)=WAIT_OBJECT_0then  Form1.Text:=Format('进程%d已关闭',[hProcess]); Result:=0;end;{启动一个进程,并建立新线程等待它的结束}procedureTForm1.Button1Click(Sender:TObject);var pInfo:TProcessInformation; sInfo:TStartupInfo; Path:array[0..MAX_PATH-1]ofChar; ThreadID:DWORD;begin {先获取记事本的路径} GetSystemDirectory(Path,MAX_PATH); StrCat(Path,'notepad.exe'); {用CreateProcess打开记事本并获取其进程句柄,然后建立线程监视} FillChar(sInfo,SizeOf(sInfo),0); ifCreateProcess(Path,nil,nil,nil,False,0,nil,nil,sInfo,pInfo)then begin  hProcess:=pInfo.hProcess;             {获取进程句柄}  Text:=Format('进程%d已启动',[hProcess]);  CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID);{建立线程监视} end;end;end.窗体文件:objectForm1:TForm1 Left=0 Top=0 Caption='Form1' ClientHeight=124 ClientWidth=241 Color=clBtnFace Font.Charset=DEFAULT_CHARSET Font.Color= clWindowText Font.Height=-11 Font.Name='Tahoma' Font.Style=[] OldCreateOrder=False PixelsPerInch=96 TextHeight=13 objectButton1:TButton  Left=88  Top=56  Width=75  Height=25  Caption='Button1'  TabOrder=0  OnClick=Button1Click endend多线程编程(10)-多线程同步之Mutex(互斥对象)。                             原理分析:  互斥对象是系统内核对象,各线程都可以拥有它,谁拥有谁就能执行;  执行完毕,用ReleaseMutex函数释放拥有权,以让其他等待的线程使用.  其他线程可用WaitForSingleObject函数排队等候(等候也可以理解为排队申请).  使用过程:varhMutex:THandle;{应该先声明一个全局的互斥句柄}CreateMutex     {建立一个互斥对象}WaitForSingleObject {用等待函数排队等候}ReleaseMutex    {释放拥有权}CloseHandle     {最后释放互斥对象}  ReleaseMutex、CloseHandle的参数都是CreateMutex返回的句柄,关键是CreateMutex函数:functionCreateMutex( lpMutexAttributes:PSecurityAttributes; bInitialOwner:BOOL;{是否让创建者(此例中是主线程)拥有该互斥对象} lpName:PWideChar  {可以给此互斥对象取个名字,如果不要名字可赋值为nil}):THandle;{1、第一个参数前面说过.2、第二个参数在这里一定要是False,如果让主线程拥有互斥,从理论上讲,得等程序退出后其他线程才有机会; 取值False时,第一个执行的线程将会最先拥有互斥对象, 一旦拥有其他线程就得先等等.3、第三个参数,如果给个名字,函数将从系统中寻找是否有重名的互斥对象,如果有则返回同名对象的存在的句柄; 如果赋值为nil将直接创建一个新的互斥对象;下个例子将会有名字.}  本例效果图:  代码文件:unitUnit1;interfaceuses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms, Dialogs,StdCtrls;type TForm1=class(TForm)  Button1:TButton;  procedureButton1Click(Sender:TObject);  procedureFormCreate(Sender:TObject);  procedureFormDestroy(Sender:TObject); end;var Form1:TForm1;implementation{$R*.dfm}var f:Integer;   {用这个变量协调一下各线程输出的位置} hMutex:THandle;{互斥对象的句柄}functionMyThreadFun(p:Pointer):DWORD;stdcall;var i,y:Integer;begin Inc(f); y:=20*f; fori:=0to50000do begin  ifWaitForSingleObject(hMutex,INFINITE)=WAIT_OBJECT_0 then  begin   Form1.Canvas.Lock;   Form1.Canvas.TextOut(20,y,IntToStr(i));   Form1.Canvas.Unlock;   Sleep(0);{稍稍耽搁一点,不然有时Canvas会协调不过来}   ReleaseMutex(hMutex);  end; end; Result:=0;end;procedureTForm1.Button1Click(Sender:TObject);var ThreadID:DWORD;begin Repaint; f:=0; CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID);end;procedureTForm1.FormCreate(Sender:TObject);begin hMutex:=CreateMutex(nil,False,nil);end;procedureTForm1.FormDestroy(Sender:TObject);begin CloseHandle(hMutex);end;end. 窗体文件:objectForm1:TForm1 Left=0 Top=0 Caption='Form1' ClientHeight=140 ClientWidth=192 Color=clBtnFace Font.Charset=DEFAULT_CHARSET Font.Color=clWindowText Font.Height=-11 Font.Name='Tahoma' Font.Style= [] OldCreateOrder=False OnCreate=FormCreate PixelsPerInch=96 TextHeight=13 objectButton1:TButton  Left=109  Top=107  Width=75  Height=25  Caption='Button1'  TabOrder=0  OnClick=Button1Click endend  SyncObjs单元下有封装好的TMutex类,好像不如Api快,内部机制也稍有区别,但使用方法差不多:unitUnit1;interfaceuses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms, Dialogs,StdCtrls;type TForm1=class(TForm)  Button1:TButton;  procedureButton1Click(Sender:TObject);  procedureFormCreate(Sender:TObject);  procedureFormDestroy(Sender:TObject); end;var Form1:TForm1;implementation{$R*.dfm}usesSyncObjs;var f:Integer; MyMutex:TMutex;functionMyThreadFun(p:Pointer):DWORD;stdcall;var i,y:Integer;begin Inc(f); y:=20*f; fori:=0to50000 do begin  ifMyMutex.WaitFor(INFINITE)=wrSignaledthen  begin   Form1.Canvas.Lock;   Form1.Canvas.TextOut(20,y,IntToStr(i));   Form1.Canvas.Unlock;   MyMutex.Release;  end; end; Result:=0;end;procedureTForm1.Button1Click(Sender:TObject);var ThreadID:DWORD;begin Repaint; f:=0; CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID);end;procedureTForm1.FormCreate(Sender:TObject);begin MyMutex:=TMutex.Create(False);end;procedureTForm1.FormDestroy(Sender:TObject);begin MyMutex.Free;end;end.多线程编程(11)-多线程同步之Mutex(互斥对象)[续]。  Mutex作为系统核心对象是可以跨进程的(临界区就不行),我们可以利用互斥对象禁止程序重复启动.  工作思路:  先用OpenMutex尝试打开一个自定义名称的Mutex对象,如果打开失败说明之前没有这个对象存在;  如果之前没有这个对象,马上用CreateMutex建立一个, 此时的程序应该是第一次启动;  再重复启动时,那个OpenMutex就有结果了,然后强制退出.  最后在程序结束时用CloseHandle释放Mutex对象.functionOpenMutex( dwDesiredAccess:DWORD;{打开权限} bInheritHandle:BOOL; {能否被当前程序创建的进程继承} pName:PWideChar    {Mutex对象的名称}):THandle;stdcall;   {成功返回Mutex的句柄;失败返回0}  注意,这里的CreateMutex函数应该有个名了,因为OpenMutex要用到;  另外,CreateMutex的第二个参数已经不重要了(也就是True和False都行),因为这里是用其名称来判断的.  程序可以这样写:unitUnit1;interfaceuses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms, Dialogs;type TForm1=class(TForm)  procedureFormCreate(Sender:TObject);  procedureFormDestroy(Sender:TObject); end;var Form1:TForm1;implementation{$R*.dfm}var hMutex:THandle;const NameMutex='MyMutex';procedureTForm1.FormCreate(Sender:TObject);begin ifOpenMutex(MUTEX_ALL_ACCESS,False,NameMutex)<>0then begin  ShowMessage('该程序已启动');  Application.Terminate; end; hMutex:=CreateMutex(nil,False, NameMutex);end;procedureTForm1.FormDestroy(Sender:TObject);begin CloseHandle(hMutex);end;end.  这一般都是写在dpr主程序里,省得让后启动的程序执行些无用的代码:programProject1;uses Forms,Windows, Unit1in'Unit1.pas'{Form1};{$R*.res}var hMutex:THandle;const NameMutex='MyMutex';begin {主线程入口} ifOpenMutex(MUTEX_ALL_ACCESS,False,NameMutex)<>0then begin  MessageBox(0,'该程序已启动','提示',MB_OK);  Application.Terminate; end; hMutex:=CreateMutex(nil,False,NameMutex); Application.Initialize; Application.MainFormOnTaskbar:=True; Application.CreateForm(TForm1,Form1); Application.Run; CloseHandle(hMutex); {主线程出口}end.多线程编程(12)-多线程同步之Semaphore(信号对象)。  之前已经有了两种多线程的同步方法:  CriticalSection(临界区)和Mutex(互斥),这两种同步方法差不多,只是作用域不同;  CriticalSection(临界区)类似于只有一个蹲位的公共厕所,只能一个个地进;  Mutex(互斥)对象类似于接力赛中的接力棒,某一时刻只能一个人持有, 谁拿着谁跑.  什么是Semaphore(信号或叫信号量)呢?  譬如到银行办业务、或者到车站买票,原来只有一个服务员,不管有多少人排队等候,业务只能一个个地来.  假如增加了业务窗口,可以同时受理几个业务呢?  这就类似与Semaphore对象,Semaphore可以同时处理等待函数(如:WaitForSingleObject)申请的几个线程.  Semaphore的工作思路如下:  1、首先要通过CreateSemaphore(安全设置,初始信号数,信号总数,信号名称)建立信号对象;  参数四:和Mutex一样,它可以有个名称,也可以没有,本例就没有要名称(nil);有名称的一般用于跨进程.  参数三:信号总数,是Semaphore最大处理能力,就像银行一共有多少个业务窗口一样;  参数二:初始信号数,这就像银行的业务窗口很多,但打开了几个可不一定,如果没打开和没有一样;  参数一:安全设置和前面一样,使用默认(nil)即可.  2、要接受Semaphore服务(或叫协调)的线程,同样需要用等待函数(如:WaitForSingleObject)排队等候;  3、当一个线程使用完一个信号,应该用ReleaseSemaphore(信号句柄,1,nil)让出可用信号给其他线程;  参数三:一般是nil,如果给个数字指针,可以接受到此时(之前)总共闲置多少个信号;  参数二:一般是1,表示增加一个可用信号;  如果要增加CreateSemaphore时的初始信号,也可以通过ReleaseSemaphore.4、最后,作为系统内核对象,要用CloseHandle关闭.  另外,在Semaphore的总数是1的情况下,就和Mutex(互斥) 一样了.  在本例中,每点击按钮,将建立一个信号总数为5的信号对象,初始信号来自Edit1;同时有5个线程去排队.  本例也附上了Delphi中TSemaphore类的例子,但没有过多地纠缠于细节,是为了尽快理出多线程的整体思路.  本例效果图:    代码文件:unitUnit1;interfaceuses Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms, Dialogs,StdCtrls;type TForm1=class(TForm)  Button1:TButton;  Edit1:TEdit;  procedureButton1Click(Sender:TObject);  procedureFormCreate(Sender:TObject);  procedureFormDestroy(Sender:TObject);  procedureEdit1KeyPress(Sender:TObject;varKey:Char); end;var Form1:TForm1;implementation{$R*.dfm}var f:Integer;     {用这个变量协调一下各线程输出的位置} hSemaphore:THandle;{信号对象的句柄}functionMyThreadFun(p:Pointer):DWORD;stdcall;var i,y:Integer;begin Inc(f); y:=20*f; ifWaitForSingleObject(hSemaphore,INFINITE)=WAIT_OBJECT_0 then begin  fori:=0to1000do  begin   Form1.Canvas.Lock;   Form1.Canvas.TextOut(20,y,IntToStr(i));   Form1.Canvas.Unlock;   Sleep(1);{以免Canvas忙不过来}  end; end; ReleaseSemaphore(hSemaphore,1,nil); Result:=0;end;procedureTForm1.Button1Click(Sender:TObject);var ThreadID:DWORD;begin {不知是不是之前创建过Semaphore对象,假如有先关闭} CloseHandle(hSemaphore); {创建Semaphore对象} hSemaphore:=CreateSemaphore(nil,StrToInt(Edit1.Text),5,nil); Self.Repaint; f:=0; CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID);end;{让Edit只接受12345五个数}procedureTForm1.Edit1KeyPress(Sender:TObject;varKey:Char);begin ifnotCharInSet(Key,['1'..'5'])thenKey:=#0;end;procedureTForm1.FormCreate(Sender:TObject);begin Edit1.Text:='1';end;procedureTForm1.FormDestroy(Sender:TObject);begin CloseHandle(hSemaphore);end;end.

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
关闭