【问题标题】:How to use TIdThreadSafe class from Indy10如何使用 Indy10 中的 TIdThreadSafe 类
【发布时间】:2012-10-29 07:53:31
【问题描述】:

如果我定义了一个新的类,我可以使用 Indy 命令 TIdThreadSafe 使类 MyPrivateClass 线程安全吗

   MyNewIndyClass = Class(TIdThreadSafe)
         FLocal :  MyPrivateClass 
         create
          ......
          end;

我的 MyPrivateClass 不是线程安全的,因为我访问了这个类中的 TList 和 TBitmap 项

如果我将 TCPServer.Onexecute 代码更改为以下样式

    ......

     aNewIndyClass  :=  MyNewIndyClass.Create; 

     aNewIndyClass.FLocal.CallFuntionA; 

     aNewIndyClass.FLocal.CallFuntionB; 

      ......

这种方法的想法:保持 MyPrivateClass 代码不变,只需在单独的类中添加对 Indy Server onexecute 的请求

【问题讨论】:

    标签: delphi indy


    【解决方案1】:

    您应该使用 TIdThreadSafe 类的 Lock() 和 Unlock() 方法。例如在 TCPServer.OnExecute() 中调用 aNewIndyClass 的方法如下:

      aNewIndyClass  :=  MyNewIndyClass.Create; 
    
      aNewIndyClass.Lock;   // This will enter TIdThreadSafe internal's Critical Section object
      try
        with aNewIndyClass do  // The code between try/finally will be "atomic"
        begin                  // i.e. no other thread will be able to do anything with your object
          ...
          FLocal.CallFuntionA; 
          FLocal.CallFuntionB; 
          ...
        end;
      finally                 // The use of TRY/FINALLY is MANDATORY when working with critical sections!
        aNewIndyClass.Unlock; // This will leave the CS
      end;
    

    此外,最好使用属性(即 getter/setter)来访问 MyNewIndyClass 类的私有或受保护成员。

    顺便说一下,如果您使用的是 Delphi 2009 及更新版本,您可以利用泛型。一个通用线程安全类的简短示例实现可能是:

      tThreadSafeObject<T: class> = class
        private
          fObject: T;
          fCriticalSection: tCriticalSection;
        public
          constructor Create(cpObject: T);  // We expect previously created object here. We own it!
                                            // TODO: Implement ownership option?
          destructor Destroy;
          function Lock: T;
          procedure Unlock;
      end;
    
    { tThreadSafe<T> }
    
    constructor tThreadSafeObject<T>.Create(cpObject: T);
    begin
      inherited Create;
      fObject := cpObject;
      fCriticalSection := TCriticalSection.Create;
    end;
    
    destructor tThreadSafeObject<T>.Destroy;
    begin
      FreeAndNil(fObject);  // In this sample implementation fObject is owned so we free it
      FreeAndNil(fCriticalSection);
      inherited Destroy;
    end;
    
    function tThreadSafeObject<T>.Lock: T;
    begin
      fCriticalSection.Enter;
      result := fObject;
    end;
    
    procedure tThreadSafeObject<T>.Unlock;
    begin
      fCriticalSection.Leave;
    end;
    

    用法:

    procedure foo;
    var 
      tsObj: tThreadSafeObject<tMyClass>;
    begin
     tsObj := tThreadSafeObject<tMyClass>.Create(tMyClass.Create);
     try      // In real World tsObj would be variable, accessed by different threads
       with tsObj.Lock do
       try
         // Do some atomic stuff here
       finally
         tsObj.Unlock;
       end;
     finally
       freeAndNil(tsObj);
     end 
    end;
    

    【讨论】:

    • 这个解决方案已经在我的电脑上运行了,现在做更多的测试
    • @user1769184,如果您觉得本文有用并回答了您的问题,请不要忘记接受它作为答案
    猜你喜欢
    • 2011-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多