二小姐的茶会吧 关注:40贴子:1,379
  • 53回复贴,共1

又来犯傻了,,,二小姐进来解救...

只看楼主收藏回复

关于多线程安全方面的概念
1/ 多个线程同时读取同一公共变量 , 应该不会有问题吧?
2/ 多个线程同时读取同实例里面的同一个属性 , 应该不会有问题吧?
3/ 多个线程同时写入一公共变量 , 应该有问题吧?
4/ 多个线程同时写入同实例里面的同一个属性 , 应该有问题吧?


IP属地:广东1楼2015-09-28 15:35回复
    @二小姐


    IP属地:广东2楼2015-09-28 15:35
    回复
      2025-06-16 16:56:03
      广告
      这个更加不明白,理应会崩溃死掉的,偏偏跑得很欢乐一点事都没有.
      unit Unit1;
      interface
      uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
      System.Classes, Vcl.Graphics,
      Vcl.Controls, System.SynCObjs, Vcl.Forms, Vcl.Dialogs, System.Threading,
      Vcl.StdCtrls;
      var
      v: integer;
      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;
      public
      { Public declarations }
      end;
      var
      Form1: TForm1;
      implementation
      {$R *.dfm}
      procedure TForm1.Button1Click(Sender: TObject);
      var
      i: integer;
      begin
      SetLength(tasks, 100);
      for i := Low(tasks) to High(tasks) do
      begin
      tasks[i] := TTask.Create(
      procedure()
      var
      i, j: integer;
      begin
      for i := 1 to 50000000 do
      begin
      v := i; //并发给全局V赋值,但不会出错?
      j := v; //并发读取v的值
      if j > 0 then
      begin
      // sleep(1);
      if TTaskStatus.Canceled = TTask.CurrentTask.Status then
      begin
      break;
      end;
      end;
      end;
      OutputDebugString('Thread Finished');
      end);
      tasks[i].Start;
      end;
      end;
      procedure TForm1.Button2Click(Sender: TObject);
      var
      i: integer;
      begin
      for i := Low(tasks) to High(tasks) do
      begin
      tasks[i].Cancel;
      end;
      end;
      procedure TForm1.FormCreate(Sender: TObject);
      begin
      Lck := TCriticalSection.Create; //根本用不上...
      end;
      procedure TForm1.FormDestroy(Sender: TObject);
      begin
      FreeAndNil(Lck);
      end;
      end.


      IP属地:广东3楼2015-09-28 15:37
      回复
        1、没有写的话没问题
        2、天知道属性在背后做了什么,没有保证,除非你查看了源码确认没问题
        3、有问题,结果难以预料
        4、同上


        IP属地:广东4楼2015-09-28 21:07
        收起回复
          注意:有问题不等价于会崩溃死掉
          你写的这代码,也就是出现会读到脏数据的问题,还不至于崩溃掉
          你在j := v后再加句 if j <> i then OutputDebugString(PChar(i.ToString() + ',' + j.ToString()));看看不就一目了然


          IP属地:广东5楼2015-09-28 21:15
          收起回复
            真那么想崩溃的话,试下这样:
            var
            t: string;
            function MyThreadFun(p: Pointer): Integer; stdcall;
            var
            i: Integer;
            begin
            for i := 1 to 100000 do
            begin
            t := i.ToString();
            end;
            Result := 0;
            end;
            procedure TForm1.Button3Click(Sender: TObject);
            var
            ID: DWORD;
            hThread: THandle;
            begin
            IsMultiThread := False;
            hThread := CreateThread(nil, 0, @MyThreadFun, nil, CREATE_SUSPENDED, ID);
            ResumeThread(hThread);
            hThread := CreateThread(nil, 0, @MyThreadFun, nil, CREATE_SUSPENDED, ID);
            ResumeThread(hThread);
            hThread := CreateThread(nil, 0, @MyThreadFun, nil, CREATE_SUSPENDED, ID);
            ResumeThread(hThread);
            Button3.Enabled := False;
            end;
            分分钟秒崩,当然如果把IsMultiThread设置为true的话,一样死不了


            IP属地:广东6楼2015-09-28 23:32
            收起回复
              好了,将v的类型从integer换为string,无论是将v作为独立公共变量还是对象里面的属性,都不会出错, Delphi真是碉堡了,...
              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;


              IP属地:广东7楼2015-09-29 09:49
              回复
                用TThread.createanonymousThread来创建独立线程,也跑得挺好, @二小姐
                这原子锁加得好,但如题要避免并发的IO操作就要自己加锁了.


                IP属地:广东8楼2015-09-29 10:05
                收起回复