RSS
热门关键字:
当前位置 : 主页>编程开发>Delphi>列表

关于线程同步的一些方法

来源:我要研发网 作者: 时间:1970-01-01 点击:



线程是进程内一个相对独立、可调度执行单元。一个应用可以有一个主线程,一个主线程可以有多个子线程,子线程还可以有自己子线程,这样就构成了多线程应用了。由于多个线程往往会同时访问同一块内存区域,频繁访问这块区域,将会增加产生线程冲突概率。一旦产生了冲突,将会造成不可预料结果(该公用区域值是不可预料)可见处理线程同步必要性。

字串4

字串6

注意:本文中出现所有代码都是用DELPHI描述,调试环境为Windows me Delphi 6。其中所涉及Windows API函数可以从MSDN获得详细文档。

字串4

字串9

首先引用一个实例来引出我们以下讨论,该实例没有采取任何措施来避免线程冲突,它主要过程为:由主线程启动两个线程对letters这个全局变量进行频繁读写,然后分别把修改结果显示到ListBox中。由于没有同步这两个线程,使得线程在修改letters时产生了不可预料结果。大家可以看看它运行结果,如图: 字串5

字串8

ListBox每一行字母都应该一致,但是上图画线处则不同,这就是线程冲突产生结果。当两个线程同时访问该共享内存时,一个线程还未对该内存修改完,另一个线程又对该内存进行了修改,由于写值过程没有被串行化,这样就产生了无效结果。可见线程同步重要性。

字串3

字串9

以下是本例代码

字串1

unit.pas文件

字串3

unit Unit1; 字串6

interface

字串7

uses

字串4

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 字串4

Dialogs, StdCtrls;

字串3

字串5

//定义窗口类

字串1

type

字串6

TForm1 = class(TForm) 字串1

ListBox1: TListBox;

字串1

ListBox2: TListBox; 字串8

Button1: TButton;

字串6

procedure Button1Click(Sender: TObject); 字串5

private 字串6

{ Private declarations } 字串4

public 字串9

{ Public declarations }

字串4

end; 字串5

字串9

//定义线程类

字串4

type

字串1

TListThread=class(TThread) 字串4

private

字串8

Str:String; 字串5

protected 字串2

procedure AddToList;//Str加入ListBox组件

字串8

Procedure Execute;override;

字串4

public

字串6

LBox:TListBox;

字串9

end;

字串4

//定义变量 字串6

var

字串2

Form1: TForm1; 字串7

Letters:String=''''AAAAAAAAAAAAAAAAAAAA'''';//全局变量 字串6

字串5

implementation

字串4

字串1

{$R *.dfm} 字串3

字串1

//线程类实现部分 字串7

procedure TListThread.Execute; 字串8

var

字串8

I,J,K:Integer;

字串8

begin

字串2

for i:=0 to 50 do 字串6

begin 字串3

for J:=1 to 20 do

字串6

for K:=1 to 1000 do//循环1000次增加产生冲突几率 字串9

if letters[j]<''''Z'''' then 字串6

letters[j]:=succ(Letters[j])

字串1

else

字串2

letters[j]:=''''A'''';

字串6

str:=letters;

字串9

synchronize(addtolist);//同步访问VCL可视组件

字串7

end; 字串2

end;

字串9

字串1

procedure TListThread.AddToList;

字串9

begin 字串7

LBox.Items.Add(str);//str加入列表框 字串8

end; 字串9

字串7

//窗口类实现部分 字串2

procedure TForm1.Button1Click(Sender: TObject); 字串3

var 字串1

th1,th2:TListThread;

字串9

begin

字串9

Listbox1.Clear;

字串8

Listbox2.Clear;

字串4

th1:=tlistThread.Create(true);//创建线程1

字串5

th2:=tlistThread.Create(true);//创建线程2 字串9

th1.LBox:=listBox1; 字串7

th2.LBox:=listBox2; 字串5

th1.Resume;//开始执行 字串5

th2.Resume; 字串9

end; 字串1

end.

字串4

字串1

由上例可见,当多个线程同时修改一个公用变量时,会产生冲突,所以我们要设法防止它,这样我们开发多线程应用才能够稳定地运行。下面我们来改进它。我们先使用临界段来串行化,实现同步。在上例unit1.pas代码uses段中加入SyncObjs单元,加入全局临界段变量(TRTLCriticalSectionCritical1,在FormCreate事件中加入InitializeCriticalSection(Critical1)这句代码,在FormDestroy事件中加入DeleteCriticalSection(Critical1)这句代码,然后修改TListThread.Execute函数,修改后代码似如下所示(处为增加代码):

字串6

procedure TListThread.Execute;

字串8

var 字串4

I,J,K:Integer;

字串4

begin

字串8

for i:=0 to 50 do

字串5

begin 字串4

►EnterCriticalSection(Critical1);//进入临界段 字串7

for J:=1 to 20 do

字串6

for K:=1 to 3000 do 字串3

if letters[j]<''''Z'''' then

字串6

letters[j]:=succ(Letters[j])

字串1

else

字串7

letters[j]:=''''A'''';

字串9

str:=letters;

字串1

►LeaveCriticalSection(Critical1);//退出临界段 字串8

synchronize(addtolist); 字串8

end;

字串2

end; 字串5

好了,重新编译,运行结果如下图所示:

字串7

字串7

程序成功避免了冲突,看来真很简单,我们成功了!当然我们还可以使用其它同步技术如Mutex(互斥对象), Semaphore(信号量)等,这些技术都是Windows通过API直接提供给我们 字串9

字串8

下面总结一下Windows常用几种线程同步技术。 字串9

1. Critical Sections(临界段),源代码中如果有不能由两个或两个以上线程同时执行部分,可以用临界段来使这部分代码执行串行化。它只能在一个独立进程或一个独立应用程序中使用。使用方法如下:
//
在窗体创建中 字串4
InitializeCriticalSection(Critical1)
//
在窗体销毁中
DeleteCriticalSection(Critical1)
//
在线程中
EnterCriticalSection(Critical1)
……
保护代码
LeaveCriticalSection(Critical1)
字串1

2. Mutex(互斥对象),是用于串行化访问资源全局对象。我们首先设置互斥对象,然后访问资源,最后释放互斥对象。在设置互斥对象时,如果另一个线程(或进程)试图设置相同互斥对象,该线程将会停下来,直到前一个线程(或进程)释放该互斥对象为止。注意它可以由不同应用程序共享。使用方法如下:
//
在窗体创建中

字串3


hMutex:=CreateMutex(nil,false,nil)
//
在窗体销毁中
CloseHandle(hMutex)
//
在线程中
WaitForSingleObject(hMutex,INFINITE)
……
保护代码
ReleaseMutex(hMutex)

字串9

3. Semaphore(信号量),它与互斥对象相似,但它可以计数。例如可以允许一个给定资源同时同时被三个线程访问。其实Mutex就是最大计数为一Semaphore。使用方法如下:
//
在窗体创建中 字串1
hSemaphore:=
CreateSemaphore(nil,lInitialCount,lMaximumCount,lpName)
//
在窗体销毁中

CloseHandle(hSemaphore)
//
在线程中
WaitForSingleObject(hSemaphore,INFINITE)
……
保护代码

字串8


ReleaseSemaphore(hSemaphore, lReleaseCount, lpPreviousCount)

字串2

4. 还可以使用DelphiTcriticalSection这个VCL对象,它定义在Syncobjs.pas中。

字串5

字串5

当你开发多线程应用时,并且多个线程同时访问一个共享资源或数据时,你需要考虑线程同步问题了。

字串9

如果你想获得本文电子版及其源代码,那么请到http://codehunter.1yes.net 网站上下载. 字串4

200195日星期三
最新评论共有 0 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册
相关文章