[简介]
常用网名: 猪头三
出生日期: 1981.XX.XX
QQ: 643439947
个人网站: 80x86汇编小站 https://www.x86asm.org
编程生涯: 2001年~至今[共22年]
职业生涯: 20年
开发语言: C/C++、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python
开发工具: Visual Studio、Delphi、XCode、Eclipse、C++ Builder
技能种类: 逆向 驱动 磁盘 文件
研发领域: Windows应用软件安全/Windows系统内核安全/Windows系统磁盘数据安全/macOS应用软件安全
项目经历: 磁盘性能优化/文件系统数据恢复/文件信息采集/敏感文件监测跟踪/网络安全检测
[序言]
本次内容主要是学习TMonitor, TEvent和TQueue配合实现TThreadQueue的经典使用案例. 本次代码的同步等待机制是使用TEvent的WaitFor(), SetEvent()和ResetEvent()方法.
[下面是经典代码]
Delphi
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages,
System.SysUtils, System.Variants, System.Classes, System.Threading, System.SyncObjs,
System.Generics.Collections,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Bn_ReadThread: TButton;
Bn_WriteThread: TButton;
Memo_Result: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure Bn_ReadThreadClick(Sender: TObject);
procedure Bn_WriteThreadClick(Sender: TObject);
private
{ Private declarations }
mpr_ShareQueue : TQueue<string> ; // 共享数据队列
mpr_Thread_Lock : TObject ; // 同步锁
mpr_Thread_event : TEvent ; // 同步事件
mpr_Threads_Count: Integer ; // 写者线程的数量
public
{ Public declarations }
procedure mpu_pro_Thread_Write(const cstr_param_Data : string) ;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
mpr_ShareQueue := TQueue<string>.Create() ;
mpr_Thread_Lock := TObject.Create();
mpr_Threads_Count := 0 ;
// 同步事件初始化: 手工设置信号, 初始化为非信号状态
mpr_Thread_event := TEvent.Create(nil, True, False,' ') ;
end;// End FormCreate()
procedure TForm1.FormShow(Sender: TObject);
begin
//
end;// End FormShow()
// 单个读者线程
procedure TForm1.Bn_ReadThreadClick(Sender: TObject);
begin
TTask.Run(procedure
var
str_Data : string ;
begin
// 循环读取
while True do
begin
// 等待共享数据队列存储新的数据
mpr_Thread_event.WaitFor(INFINITE) ;
// 启动同步锁
System.TMonitor.Enter(mpr_Thread_Lock) ;
try
// 获取数据之后, 同步在界面上显式
if mpr_ShareQueue.Count > 0 then
begin
str_Data := mpr_ShareQueue.Dequeue ;
// 如果共享数据队列没有数据, 那么则通知读者线程进入等待状态
if mpr_ShareQueue.Count = 0 then
begin
mpr_Thread_event.ResetEvent() ;
end;
// 界面显式数据
TThread.Synchronize(TThread.Current, procedure
begin
Memo_Result.Lines.Add(str_Data) ;
end);
end;
finally
System.TMonitor.Exit(mpr_Thread_Lock) ;
end;
end;
end);
end;// End Bn_ReadThreadClick()
procedure TForm1.mpu_pro_Thread_Write(const cstr_param_Data : string) ;
begin
TTask.Run(procedure
begin
// 随机休眠时间
TThread.Sleep((Random(5)+1)*1000) ;
// 向共享数据队列添加数据
// 启动同步锁
System.TMonitor.Enter(mpr_Thread_Lock) ;
try
mpr_ShareQueue.Enqueue(cstr_param_Data) ;
// 向读者线程发出信号, 共享数据队列有新数据进入
mpr_Thread_event.SetEvent();
finally
System.TMonitor.Exit(mpr_Thread_Lock) ;
end;
end);
end;// End mpu_pro_Thread_Write()
procedure TForm1.Bn_WriteThreadClick(Sender: TObject);
var
str_Data : string ;
begin
Inc(mpr_Threads_Count) ;
str_Data := Format('%d 号线程的数据.', [mpr_Threads_Count]) ;
Bn_WriteThread.Caption := Format('2: 创建写入线程(%d)', [mpr_Threads_Count]) ;
mpu_pro_Thread_Write(str_Data) ;
end;// End Bn_WriteThreadClick()
end.
[结尾]
上面的代码, 需要注意的细节是: TEvent的WaitFor(), SetEvent()和ResetEvent()替换了TMonitor.Wait()和TMonitor.Pulse()的等待与唤醒同步操作.