关于新版Delphi的并发操作及公共变量并发读写

传统的编译型语言对多线程访问同一公共变量都会先锁定,旧版的Delphi亦如是,如果不先锁定,多半会有地址操作错误之类的运行时提示.

  但XE的出现让一切都免了,固定内存占用的数据类型(integer,double,long之类)同时读写没事, 即使变长的String类型亦没事!! 除了公共变量, 连对象的属性都一样,下面是测试代码:

  1. type  
  2.   TForm1 = class(TForm)  
  3.     Button1: TButton;  
  4.     Button2: TButton;  
  5.     procedure Button1Click(Sender: TObject);  
  6.     procedure FormCreate(Sender: TObject);  
  7.     procedure FormDestroy(Sender: TObject);  
  8.     procedure Button2Click(Sender: TObject);  
  9.   private  
  10.     { Private declarations }  
  11.     Lck: TCriticalSection;  
  12.     tasks: array of ITask;  
  13.     fv: String;  
  14.   public  
  15.     { Public declarations }  
  16.     property v:String read fv write fv;  
  17.   end;  
  18.   
  19. var  
  20.   Form1: TForm1;  
  21.   
  22. implementation  
  23.   
  24. {$R *.dfm}  
  25.   
  26. procedure TForm1.Button1Click(Sender: TObject);  
  27. var  
  28.   i: integer;  
  29. begin  
  30.   SetLength(tasks, 150);  
  31.   for i := Low(tasks) to High(tasks) do  
  32.   begin  
  33.     tasks[i] := TTask.Create(  
  34.       procedure()  
  35.       var  
  36.         i, j: integer;  
  37.       begin  
  38.         for i := 1 to 500000000 do  
  39.         begin  
  40.           Form1.v := inttostr(i); // 并发给全局V赋值,但不会出错?  
  41.           j := strtoint(Form1.v); // 并发读取v的值  
  42.           if j <> i then  
  43.           begin  
  44.             // OutputDebugString(pchar(format('%d,%d',[j,i])));  
  45.           end;  
  46.           if TTaskStatus.Canceled = TTask.CurrentTask.Status then  
  47.           begin  
  48.             break;  
  49.           end;  
  50.           sleep(random(5));  
  51.         end;  
  52.         OutputDebugString('Thread Finished');  
  53.       end);  
  54.     tasks[i].Start;  
  55.   end;  
  56. end;  

      

改为用TThread也一样没事!

  1. threads:array of tthread;  
  2. procedure TForm1.Button3Click(Sender: TObject);  
  3. var  
  4.   i: integer;  
  5. begin  
  6.    tag:=0;  
  7.   SetLength(threads,150);  
  8.   for i := 0 to 149 do  
  9.   begin  
  10.     threads[i] := TThread.CreateAnonymousThread(  
  11.       procedure()  
  12.       var  
  13.         i, j: integer;  
  14.       begin  
  15.         OutputDebugString(pchar('Thread '+INTTOSTR(tthread.CurrentThread.Handle)+' started.'));  
  16.         for i := 1 to 500000000 do  
  17.         begin  
  18.           Form1.v := inttostr(i); // 并发给全局V赋值,但不会出错?  
  19.           j := strtoint(Form1.v); // 并发读取v的值  
  20.           if j <> i then  
  21.           begin  
  22.             // OutputDebugString(pchar(format('%d,%d',[j,i])));  
  23.           end;  
  24.           if form1.Tag<>0 then  
  25.           begin  
  26.             break;  
  27.           end;  
  28.           sleep(random(5));  
  29.         end;  
  30.         OutputDebugString('Thread Finished');  
  31.       end);  
  32.     threads[i].FreeOnTerminate := true;  
  33.     threads[i].Start;  
  34.   end;  
  35. end;  


为什么那么神奇?? 二小姐的回复说 ismulthread是System单元里的一个开关,表示是否运行在多线程模式中,多线程模式下fastmm会给分配内存之类的操作用原子指令来加锁,用Task和TThread之类不用设置这个变量,它们内部本身就有设置. 不得不给XE点100个赞.


但是问题来了, 是不是所有数据类型都能自动处理?? 并不是,若将fv改为TDictionary<integer,String>,如下:

  1. type  
  2.   TForm1 = class(TForm)  
  3.     Button1: TButton;  
  4.     Button2: TButton;  
  5.     Button3: TButton;  
  6.     Button4: TButton;  
  7.     procedure Button1Click(Sender: TObject);  
  8.     procedure FormCreate(Sender: TObject);  
  9.     procedure FormDestroy(Sender: TObject);  
  10.     procedure Button2Click(Sender: TObject);  
  11.     procedure Button3Click(Sender: TObject);  
  12.     procedure Button4Click(Sender: TObject);  
  13.   private  
  14.     { Private declarations }  
  15.     Lck: TCriticalSection;  
  16.     tasks: array of ITask;  
  17.     threads:array of tthread;  
  18.     fv:TDictionary<integer,String>;  
  19.   public  
  20.     { Public declarations }  
  21.     property v: TDictionary<integer,String> read fv write fv;  
  22.   end;  
  23.   
  24. var  
  25.   Form1: TForm1;  
  26.   
  27. implementation  
  28.   
  29. {$R *.dfm}  
  30.   
  31. procedure TForm1.Button1Click(Sender: TObject);  
  32. var  
  33.   i: integer;  
  34. begin  
  35.   SetLength(tasks, 150);  
  36.   for i := Low(tasks) to High(tasks) do  
  37.   begin  
  38.     tasks[i] := TTask.Create(  
  39.       procedure()  
  40.       var  
  41.         i, j: integer;  
  42.       begin  
  43.         for i := 1 to 500000000 do  
  44.         begin  
  45.           Form1.v.AddOrSetValue(i,inttostr(i)); // 并发给全局V赋值,但不会出错?  
  46.           j := strtoint(Form1.v.Items[i]); // 并发读取v的值  
  47.           if j <> i then  
  48.           begin  
  49.             // OutputDebugString(pchar(format('%d,%d',[j,i])));  
  50.           end;  
  51.           if TTaskStatus.Canceled = TTask.CurrentTask.Status then  
  52.           begin  
  53.             break;  
  54.           end;  
  55.           sleep(random(5));  
  56.         end;  
  57.         OutputDebugString('Thread Finished');  
  58.       end);  
  59.     tasks[i].Start;  
  60.   end;  
  61. end;  

因为TDictionary是个比较复杂的类,存取里面的代码复杂, fastmm内置的原子锁就无能为力了, 运行一会就出现write 地址出错 .
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值