关于新版Delphi的并发操作及公共变量并发读写
发布时间:2020-12-15 09:58:05 所属栏目:大数据 来源:网络整理
导读:? ? ? ? 传统的编译型语言对多线程访问同一公共变量都会先锁定,旧版的Delphi亦如是,如果不先锁定,多半会有地址操作错误之类的运行时提示. 但XE的出现让一切都免了,固定内存占用的数据类型(integer,double,long之类)同时读写没事,即使变长的String类型亦没事
? ? ? ? 传统的编译型语言对多线程访问同一公共变量都会先锁定,旧版的Delphi亦如是,如果不先锁定,多半会有地址操作错误之类的运行时提示. 但XE的出现让一切都免了,固定内存占用的数据类型(integer,double,long之类)同时读写没事,即使变长的String类型亦没事!! 除了公共变量,连对象的属性都一样,下面是测试代码: 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也一样没事! 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,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>,如下:
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,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,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 地址出错 . (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |