Delphi多线程编程之五不同类线程读写全局变量-阻塞和锁定
(调试环境:Delphi2007+WinXPsp3 例程:Tst_Thread5.dpr)
前面的例子都是同类线程的不同实例来读写全局变量,用临界区、互斥等来锁住同段代码。现在碰到的问题是,A,B两个不同类型的线程,如何安全地来读写全局变量。
unit Tst_Thread5U;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,SyncObjs;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TFirstThread=Class(TThread)
protected
procedure Execute;override;
procedure ShowNum;
end;
TSecondThread=Class(TThread)
protected
procedure Execute;override;
procedure ShowNum;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
MaxSize=12;
var
WhichRun:integer;
GlobalArry:array[1..MaxSize] of Integer;
LockCS:TCriticalSection; //uses SyncObjs
LockMREWS:TMultiReadExclusiveWriteSynchronizer; //uses SysUtils
//===============
procedure AddNum;
var
i,j:integer;
begin
if WhichRun=2 then LockCS.Acquire;
if WhichRun=3 then LockMREWS.BeginRead;
j:=GlobalArry[MaxSize];
if WhichRun=3 then LockMREWS.EndRead;
if WhichRun=3 then LockMREWS.BeginWrite;
for i := 1 to MaxSize do
begin
GlobalArry[i]:=j;
inc(j);
Sleep(5);
end;
if WhichRun=2 then LockCS.Release;
if WhichRun=3 then LockMREWS.EndWrite;
end;
procedure TFirstThread.Execute;
begin
FreeOnTerminate:=True;
AddNum;
Synchronize(ShowNum);
end;
procedure TFirstThread.ShowNum;
var
i:integer;
begin
for i := 1 to MaxSize do
Form1.Memo1.Lines.Add(inttostr(GlobalArry[i]));
end;
procedure TSecondThread.Execute;
begin
FreeOnTerminate:=True;
AddNum;
Synchronize(ShowNum);
end;
procedure TSecondThread.ShowNum;
var
i:integer;
begin
for i := 1 to MaxSize do
Form1.Memo1.Lines.Add(inttostr(GlobalArry[i]));
end;
//未阻塞
procedure TForm1.Button1Click(Sender: TObject);
begin
WhichRun:=1;
TFirstThread.Create(False);
TSecondThread.Create(False);
end;
//阻塞 TCriticalSection
procedure TForm1.Button2Click(Sender: TObject);
begin
WhichRun:=2;
TFirstThread.Create(False);
TSecondThread.Create(False);
end;
//TMREWS
procedure TForm1.Button3Click(Sender: TObject);
begin
WhichRun:=3;
TFirstThread.Create(False);
TSecondThread.Create(False);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
LockCS:=TCriticalSection.Create;
LockMREWS:=TMultiReadExclusiveWriteSynchronizer.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
LockCS.Free;
LockMREWS.Free;
end;
end.
一、用TCriticalSection类来阻塞。(ps:这里的咚咚都涉及Win32编程,我对这些不了解,先掌握如何运用吧。)这个有点类似临界区。要Uses SyncObjs单元。
1、声明一个全局的TCriticalSection类的实例。
2、建立TCriticalSection.Create,最好是在程序onCreate里面,这样才能保证对所有线程进行控制。
3、在全局变量访问前用TCriticalSection.Acquire或TCriticalSection.Enter来阻塞。
4、访问完毕,用TCriticalSection.Release或TCriticalSection.Leave来解除阻塞。
5、在恰当的位置进行TCriticalSection.Free,一般在程序的onDestroy里。
二、用TMultiReadExclusiveWriteSynchronizer类来阻塞。可以写成TMREWSync。这个类在SysUtils单元里。(ps:天哪,那么长的单词我第一次见)。TMultiReadExclusiveWriteSynchronizer和TCriticalSection不同的是,它允许多个线程同时读一个变量,只是在写一个变量时才需要事先阻塞,因为只有多个线程同时写一个变量才有可能造成冲突。
使用TMREWS的优势是它允许多线程的并发读取,同时又与CriticalSection一样允许读的时候只有一个线程访问。劣势是TMREWS用起来要费更高的代价。
1、声明一个全局的TMultiReadExclusiveWriteSynchronizer类的实例。
2、建立TMultiReadExclusiveWriteSynchronizer.Create。
3、每个线程在读一个全局变量前要先调用该类的BeginRead()来检查是否有其他线程在写这个变量。如果有,就等待,直到其他线程不再写这个变量才返回。当读好后,调用EndRead()来结束。
如果一个线程要写这个变量,必须先调用BeginWrite()来检查当前是否有其他现成在写这个变量并且所有线程是否都调用了EndRead()。只要有一个线程正在写这个变量,或者有一个线程还没有调用EndRead(),BeginWrite()将一直等待。当线程写完以后,必须及时地调用EndWrite(),一边其他线程可以读写这个全局变量。
4、在恰当的位置进行Free,一般在程序的onDestroy里。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库