关于新版Delphi的并发操作及公共变量并发读写
2017-03-23 08:08
513 查看
传统的编译型语言对多线程访问同一公共变量都会先锁定,旧版的Delphi亦如是,如果不先锁定,多半会有地址操作错误之类的运行时提示.
但XE的出现让一切都免了,固定内存占用的数据类型(integer,double,long之类)同时读写没事, 即使变长的String类型亦没事!! 除了公共变量, 连对象的属性都一样,下面是测试代码:
[delphi]
view plain
copy
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
Lck: TCriticalSection;
tasks: array of ITask;
fv: String;
public
{ Public declarations }
property v:String read fv write fv;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
begin
SetLength(tasks, 150);
for i := Low(tasks) to High(tasks) do
begin
tasks[i] := TTask.Create(
procedure()
var
i, j: integer;
begin
for i := 1 to 500000000 do
begin
Form1.v := inttostr(i); // 并发给全局V赋值,但不会出错?
j := strtoint(Form1.v); // 并发读取v的值
if j <> i then
begin
// OutputDebugString(pchar(format('%d,%d',[j,i])));
end;
if TTaskStatus.Canceled = TTask.CurrentTask.Status then
begin
break;
end;
sleep(random(5));
end;
OutputDebugString('Thread Finished');
end);
tasks[i].Start;
end;
end;
改为用TThread也一样没事!
[delphi]
view plain
copy
threads:array of tthread;
procedure TForm1.Button3Click(Sender: TObject);
var
i: integer;
begin
tag:=0;
SetLength(threads,150);
for i := 0 to 149 do
begin
threads[i] := TThread.CreateAnonymousThread(
procedure()
var
i, j: integer;
begin
OutputDebugString(pchar('Thread '+INTTOSTR(tthread.CurrentThread.Handle)+' started.'));
for i := 1 to 500000000 do
begin
Form1.v := inttostr(i); // 并发给全局V赋值,但不会出错?
j := strtoint(Form1.v); // 并发读取v的值
if j <> i then
begin
// OutputDebugString(pchar(format('%d,%d',[j,i])));
end;
if form1.Tag<>0 then
begin
break;
end;
sleep(random(5));
end;
OutputDebugString('Thread Finished');
end);
threads[i].FreeOnTerminate := true;
threads[i].Start;
end;
end;
为什么那么神奇?? 二小姐的回复说 ismulthread是System单元里的一个开关,表示是否运行在多线程模式中,多线程模式下fastmm会给分配内存之类的操作用原子指令来加锁,用Task和TThread之类不用设置这个变量,它们内部本身就有设置. 不得不给XE点100个赞.
但是问题来了,
是不是所有数据类型都能自动处理?? 并不是,若将fv改为TDictionary<integer,String>,如下:
[delphi]
view plain
copy
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
Lck: TCriticalSection;
tasks: array of ITask;
threads:array of tthread;
fv:TDictionary<integer,String>;
public
{ Public declarations }
property v: TDictionary<integer,String> read fv write fv;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
begin
SetLength(tasks, 150);
for i := Low(tasks) to High(tasks) do
begin
tasks[i] := TTask.Create(
procedure()
var
i, j: integer;
begin
for i := 1 to 500000000 do
begin
Form1.v.AddOrSetValue(i,inttostr(i)); // 并发给全局V赋值,但不会出错?
j := strtoint(Form1.v.Items[i]); // 并发读取v的值
if j <> i then
begin
// OutputDebugString(pchar(format('%d,%d',[j,i])));
end;
if TTaskStatus.Canceled = TTask.CurrentTask.Status then
begin
break;
end;
sleep(random(5));
end;
OutputDebugString('Thread Finished');
end);
tasks[i].Start;
end;
end;
因为TDictionary是个比较复杂的类,存取里面的代码复杂, fastmm内置的原子锁就无能为力了, 运行一会就出现write 地址出错 .
但XE的出现让一切都免了,固定内存占用的数据类型(integer,double,long之类)同时读写没事, 即使变长的String类型亦没事!! 除了公共变量, 连对象的属性都一样,下面是测试代码:
[delphi]
view plain
copy
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
Lck: TCriticalSection;
tasks: array of ITask;
fv: String;
public
{ Public declarations }
property v:String read fv write fv;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
begin
SetLength(tasks, 150);
for i := Low(tasks) to High(tasks) do
begin
tasks[i] := TTask.Create(
procedure()
var
i, j: integer;
begin
for i := 1 to 500000000 do
begin
Form1.v := inttostr(i); // 并发给全局V赋值,但不会出错?
j := strtoint(Form1.v); // 并发读取v的值
if j <> i then
begin
// OutputDebugString(pchar(format('%d,%d',[j,i])));
end;
if TTaskStatus.Canceled = TTask.CurrentTask.Status then
begin
break;
end;
sleep(random(5));
end;
OutputDebugString('Thread Finished');
end);
tasks[i].Start;
end;
end;
改为用TThread也一样没事!
[delphi]
view plain
copy
threads:array of tthread;
procedure TForm1.Button3Click(Sender: TObject);
var
i: integer;
begin
tag:=0;
SetLength(threads,150);
for i := 0 to 149 do
begin
threads[i] := TThread.CreateAnonymousThread(
procedure()
var
i, j: integer;
begin
OutputDebugString(pchar('Thread '+INTTOSTR(tthread.CurrentThread.Handle)+' started.'));
for i := 1 to 500000000 do
begin
Form1.v := inttostr(i); // 并发给全局V赋值,但不会出错?
j := strtoint(Form1.v); // 并发读取v的值
if j <> i then
begin
// OutputDebugString(pchar(format('%d,%d',[j,i])));
end;
if form1.Tag<>0 then
begin
break;
end;
sleep(random(5));
end;
OutputDebugString('Thread Finished');
end);
threads[i].FreeOnTerminate := true;
threads[i].Start;
end;
end;
为什么那么神奇?? 二小姐的回复说 ismulthread是System单元里的一个开关,表示是否运行在多线程模式中,多线程模式下fastmm会给分配内存之类的操作用原子指令来加锁,用Task和TThread之类不用设置这个变量,它们内部本身就有设置. 不得不给XE点100个赞.
但是问题来了,
是不是所有数据类型都能自动处理?? 并不是,若将fv改为TDictionary<integer,String>,如下:
[delphi]
view plain
copy
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
Lck: TCriticalSection;
tasks: array of ITask;
threads:array of tthread;
fv:TDictionary<integer,String>;
public
{ Public declarations }
property v: TDictionary<integer,String> read fv write fv;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
begin
SetLength(tasks, 150);
for i := Low(tasks) to High(tasks) do
begin
tasks[i] := TTask.Create(
procedure()
var
i, j: integer;
begin
for i := 1 to 500000000 do
begin
Form1.v.AddOrSetValue(i,inttostr(i)); // 并发给全局V赋值,但不会出错?
j := strtoint(Form1.v.Items[i]); // 并发读取v的值
if j <> i then
begin
// OutputDebugString(pchar(format('%d,%d',[j,i])));
end;
if TTaskStatus.Canceled = TTask.CurrentTask.Status then
begin
break;
end;
sleep(random(5));
end;
OutputDebugString('Thread Finished');
end);
tasks[i].Start;
end;
end;
因为TDictionary是个比较复杂的类,存取里面的代码复杂, fastmm内置的原子锁就无能为力了, 运行一会就出现write 地址出错 .
相关文章推荐
- 关于新版Delphi的并发操作及公共变量并发读写
- 关于如何操作其他窗体的控件或变量的方法!
- 关于delphi的log的class已经完成,一如既往的open 他delphi ,日志class,临界区,文件操作
- Delphi中关于动态数组的引用操作
- 多线程环境下对变量的读写操作的原子性问题(一道百度笔试题引发的思考)
- delphi多线程访问公共变量
- 关于如何操作其他窗体的控件或变量的方法
- 关于 Delphi 中流的使用(2) 用 TFileStream(文件流) 读写
- Delphi关于记录文件的操作
- Delphi关于记录文件的操作-转
- oracle的读写表并发操作
- DELPHI关于文件操作集锦
- DELPHI中关于读写INI文件的详细解说[转]
- ubuntu8.04关于公共环境变量的设置
- C#中关于文件读写操作和注册表操作
- Delphi关于Excel的操作
- 关于 Delphi 中流的使用(2) 用 TFileStream(文件流) 读写
- 公共表表达式和表变量不会触发CPU的并发效果
- delphi多线程访问公共变量
- delphi多线程访问公共变量