多线程同步 CS : TCriticalSection; 定义放在哪里?

疯狂低调 2008-11-03 11:22:25
在主窗口中含有两个公共变量 pbArray 、pb,两个线程同时写入改两个变量的内容。 未防止同步错误,加入了 CS : TCriticalSection ,但不清楚下面的定义及使用方法是否有错?
另外:如果没有错误的话,在每个线程内部定义的局部 CS : TCriticalSection在进行同步操作时如何确定另外线程的 CS : TCriticalSection对象能够正确被使用,而不是同时都使用?
线程1

procedure TH1.Execute;
var
n : integer;
CS : TCriticalSection;
begin
{ Place thread code here }
CS := TCriticalSection.Create;
form1.Label1.Caption := IntToStr(self.ThreadID);
while not Self.Terminated do
begin
sleep(20);
for n := 0 to high(Form1.pbArray) do
begin

form1.ProgressBar1.Position := n;

CS.Acquire;
try
form1.pbArray[n] := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
form1.pb := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
finally
CS.Release;
end;
end;

//CRITICAL_SECTION
end;

end;




线程2

procedure TH2.Execute;
var
n : integer;
CS : TCriticalSection;
begin

{ Place thread code here }
CS := TCriticalSection.Create;
form1.Label2.Caption := IntToStr(self.ThreadID);
while not Self.Terminated do
begin
sleep(20);
for n := 0 to high(Form1.pbArray) do
begin

form1.ProgressBar2.Position := n;

CS.Acquire;
try
form1.pbArray[n] := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
form1.pb := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
finally
CS.Release;
end;
end;



end;

end;
...全文
941 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
CaiBirdy 2008-11-03
  • 打赏
  • 举报
回复
内核对象比全局变量还全局,,你认为它是放哪里的。。?
疯狂低调 2008-11-03
  • 打赏
  • 举报
回复
随后我又写了如下的解决办法,请问高手哪种比较可取,需要注意些什么?

主窗体代码:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, unit2,unit3,SyncObjs;

type
TForm1 = class(TForm)
ProgressBar1: TProgressBar;
ProgressBar2: TProgressBar;
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }

t1 : TH1;
t2 : TH2;
public
{ Public declarations }
pbArray : array[0..2000] of string;
pb : string;
//CS : TCriticalSection;

end;

var
Form1: TForm1;
Lock : TRTLCriticalSection;
implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
begin

t1 := TH1.Create(false);

t2 := TH2.Create(false);

end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
t1.Terminate;
t2.Terminate;

FreeAndNil(t1);
FreeAndNil(t2);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
InitializeCriticalSection(Lock);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
DeleteCriticalSection(Lock);

end;

end.




线程1代码:

unit Unit2;

interface

uses
Classes,SysUtils,SyncObjs,Windows;

type
TH1 = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;

implementation

{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

procedure TH1.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }

{ TH1 }
uses
unit1;
procedure TH1.Execute;
var
n : integer;
//CS : TCriticalSection;
begin
{ Place thread code here }
//CS := TCriticalSection.Create;
form1.Label1.Caption := IntToStr(self.ThreadID);
while not Self.Terminated do
begin
sleep(20);
for n := 0 to high(Form1.pbArray) do
begin

form1.ProgressBar1.Position := n;

//CS.Acquire;
EnterCriticalSection(lock);

try
form1.pbArray[n] := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
form1.pb := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
finally
//CS.Release;
LeaveCriticalSection(lock);
end;
end;

//CRITICAL_SECTION
end;

end;

end.

{

var criticalsection: TCriticalsection;
创建:criticalsection := TCriticalsection.create;
使用:
criticalsection.enter;
try
...
finally
criticalsection.leave;
end;
}



线程2代码

unit Unit3;

interface

uses
Classes,SysUtils,SyncObjs,Windows;

type
TH2 = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;

implementation

{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

procedure TH2.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }

{ TH2 }
uses
unit1;
procedure TH2.Execute;
var
n : integer;
//CS : TCriticalSection;
begin

{ Place thread code here }
//CS := TCriticalSection.Create;
form1.Label2.Caption := IntToStr(self.ThreadID);
while not Self.Terminated do
begin
sleep(20);
for n := 0 to high(Form1.pbArray) do
begin

form1.ProgressBar2.Position := n;
EnterCriticalSection(lock);

try
form1.pbArray[n] := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
form1.pb := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
finally
//CS.Release;
LeaveCriticalSection(lock);
end;


{
CS.Acquire;
try
form1.pbArray[n] := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
form1.pb := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
finally
CS.Release;
end;
}
end;



end;

end;

end.

lake_cx 2008-11-03
  • 打赏
  • 举报
回复
放在哪我管不着,我只能告诉你
一个TCriticalSection表示一个临界区,你就看成一张门,门里面只能有一个线程进去,如果里面有线程,其他线程就进不去,知道其他线程出来。
你如果创建了两个TCriticalSection,那就表示有两张门,如果线程要同步访问一个对象或内存,你应该只给它们搞一张门。
mygodsos 2008-11-03
  • 打赏
  • 举报
回复
要区分读写的比较复杂,用用TMultiReadExclusiveWriteSynchronizer类来阻塞,可以写成TMREWSync

这样随便你,你想阻塞读或者写都成。
疯狂低调 2008-11-03
  • 打赏
  • 举报
回复
多谢楼上几位的帮忙,已对临界区有了些许的概念,似乎我只需要在写公共变量时加入临界区机制即可,读取操作应该不用临界区参与吧?
mygodsos 2008-11-03
  • 打赏
  • 举报
回复
一、临界区
所谓临界区,就是一次只能由一个线程来执行的一段代码。如果把初始化数组的代码放在临界区内,另一个线程在第一个线程处理完之前是不会被执行的。
使用临界区的步骤:
1、先声明一个全局变量类型为TRTLCriticalSection;
2、在线程Create()前调用InitializeCriticalSection()过程来初始化,该函数定义是:
void WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
类型lpCriticalSection即是Delphi封装的TRTLCriticalSection。
3、在线程的需要放入临界区的代码前面使用EnterCriticalSection(lpCriticalSection)过程来开始建立临界区。在代码完成后用LeaveCriticalSection(lpCriticalSection)来标志临界区的结束。
4、在线程执行完后用DeleteCriticalSection(lpCriticalSection)来清除临界区。这个清除过程必须放在线程执行完后的地方,比如FormDesroy事件中。上面的例子中,若把该过程放在TMyThread.Create(False);后,会产生错误。

=================
主要目的是把读写全局数据的语句放在临界区去,这样在一个线程读写完成全,另一个线程会等待

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧