Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 如何在多线程应用程序中保护和访问嵌套对象_Multithreading_Delphi_Critical Section_Delphi Xe8 - Fatal编程技术网

Multithreading 如何在多线程应用程序中保护和访问嵌套对象

Multithreading 如何在多线程应用程序中保护和访问嵌套对象,multithreading,delphi,critical-section,delphi-xe8,Multithreading,Delphi,Critical Section,Delphi Xe8,我有一个嵌套对象的对象。对象组织的简单示意图如下: TMainObj -TState -TDescriptor -List<TSubObj> --TSubObj_n ---TSubObjState ---TSubObjDesc ---TSubObjData type TState = class end; type TDesc = class end; type TSubObjState = class end; type TSubObjDesc = class end;

我有一个嵌套对象的对象。对象组织的简单示意图如下:

TMainObj
-TState
-TDescriptor
-List<TSubObj>
--TSubObj_n
---TSubObjState
---TSubObjDesc
---TSubObjData

type TState = class
end;

type TDesc = class
end;

type TSubObjState = class
end;

type TSubObjDesc = class
end;

type TSubObjData = class
end;

type TSubObj = class
  FSubObjState: TSubObjState;
  FSubObjDesc: TSubObjDesc;
  FSubObjData: TSubObjData;
end;

type TListSubObj = class (TList<TSubObj>)
end;

type TMainObj = class
  FState: TState;
  FDesc: TDesc;
  FList: TList<TSubObj>
end;
其他线程都必须等待访问

但当我需要访问子类TDescriptor时该怎么办?我可以这样做:

TMainObj.Lock
try
  TMainObj.Descriptor.DataLen := 1024;
  TManiObj.Descriptor.Count   := 10;
finally
  TMainObj.Unlock;
end;
完整的TMainObj将被锁定。所有其他线程都需要等待,即使它们对更改TMainObj的属性不感兴趣

或者通过这种方式仅锁定子对象描述符:

Thread1:
    TMainObj.Descriptor.Lock
    try
      TMainObj.Descriptor.DataLen := 1024;
      TManiObj.Descriptor.Count   := 10;
    finally
      TMainObj.Descriptor.Unlock;
    end;
同时,其他一些线程仍然可以访问TMainObj属性并更改它们,对吗

Thread2: 
    TMainObj.Lock;
    try
      TMainObj.Name := 'New name!';
    finally
      TMainObj.Unlock;
    end;
下面的图片显示了每个线程访问的方式和内容

令人关切的问题之一是僵局。在下一个例子中,我想展示不同的线程如何访问MainObj的不同“部分”

主线程:

MainObj.Lock;
try
  MainObj.Name = 'Different name!'
  MainObj.Id   = 2;
finally
MainObj.Unlock;
end;
与此同时,thread1正在执行以下操作:

MainObj.Descriptor.Lock;
try
   MainObj.Descriptor.DataLen = 1024;
   MainObj.Descriptor.Count   = 1;
finally
  MainObj.Descriptor.Unlock;
end;
所以两者都在共享MainObj,但每个都在更改对象的自己部分。这种锁定方法合适吗

我希望我能尽可能清楚地解释我的问题。我的问题是如何保护不同线程对此类对象结构的访问?我是否必须使用每个子对象自己的锁定/解锁对方法(和关键部分)来保护每个子对象

您可以在不向对象添加任何内容的情况下使用它。在这种情况下,您的代码如下所示:

TMonitor.Enter(MainObj.Descriptor);
try
  MainObj.Descriptor.DataLen := 1024;
  MainObj.Descriptor.Count   := 10;
finally
  TMonitor.Exit(MainObj.Descriptor);
end;
Main Thread
  Lock MainObj
  Lock MainObj.Descriptor (waits for thread 1)
如果所有试图访问描述符的线程(和主线程)都执行相同的操作,那么它们将锁定,等待下一个线程完成

你需要注意死锁,但从你所说的来看,这不应该是一个问题。如果执行以下操作,将发生死锁:

TMonitor.Enter(MainObj.Descriptor);
try
  MainObj.Descriptor.DataLen := 1024;
  MainObj.Descriptor.Count   := 10;
finally
  TMonitor.Exit(MainObj.Descriptor);
end;
Main Thread
  Lock MainObj
  Lock MainObj.Descriptor (waits for thread 1)
如果线程1出现并执行此操作:

Thread 1
  Lock MainObj.Descriptor
  Lock MainObj (waits for main thread)

主线程正在使用TMainObject及其属性和子对象(TState、tddescription)。我有额外的线程。一个只使用TState,另一个只使用TDDescription。因此,每个线程都与主线程共享一些内容。因此,当主线程仅更改Main对象上的属性时,锁必须仅锁定这些属性,而其他线程仍可以更改TState或TDescriptor对象。我的问题是,我是否可以只锁定对象的某些部分,还是应该锁定完整的对象?如果没有完整的图片,很难建议您,在我的视图中,请添加一个带有Delphi版本的标记-可用的线程代码各不相同。这正是我关心的问题。具有嵌套对象时的死锁情况。首先,我需要弄清楚在我的案例中是否会出现任何可能导致这种僵局的情况。我读了Eric Grange的一篇文章,比较了TCriticalSection和TMonitor,他的结论是如果性能重要,就不使用TMonitor,所以我认为使用TCriticalSection是更好的选择。TMonitor在性能方面有了一些改进。请阅读Eric博客中的评论。在Windows上,我认为如果要使用本机进程内锁这一关键部分,您必须近乎疯狂地拒绝。TMonitor的记录很差。