Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.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 Delphi线程-需要保护/同步代码的哪些部分?_Multithreading_Delphi - Fatal编程技术网

Multithreading Delphi线程-需要保护/同步代码的哪些部分?

Multithreading Delphi线程-需要保护/同步代码的哪些部分?,multithreading,delphi,Multithreading,Delphi,到目前为止,我认为在“共享”对象(多线程通用)上执行的任何操作都必须使用“同步”进行保护,无论发生什么情况。显然,我错了——在我最近研究的代码中有很多类(如作者所说的线程安全类),其中只有一个对几乎所有方法都使用了临界部分 如何找到代码中哪些部分/方法需要使用CriticalSection(或任何其他方法)进行保护,哪些不需要 到目前为止,我还没有发现任何有趣的解释/文章/博客注释,所有谷歌结果都是: a) 线程和GUI之间的同步示例。从简单的progressbar到最复杂的progressba

到目前为止,我认为在“共享”对象(多线程通用)上执行的任何操作都必须使用“同步”进行保护,无论发生什么情况。显然,我错了——在我最近研究的代码中有很多类(如作者所说的线程安全类),其中只有一个对几乎所有方法都使用了临界部分

如何找到代码中哪些部分/方法需要使用CriticalSection(或任何其他方法)进行保护,哪些不需要

到目前为止,我还没有发现任何有趣的解释/文章/博客注释,所有谷歌结果都是:

a) 线程和GUI之间的同步示例。从简单的progressbar到最复杂的progressbar,教训是显而易见的:每次访问/修改GUI组件的属性时,都要在“同步”中进行。但没别的了

b) 文章解释了关键部分、互斥体等。只是一种不同的保护/同步方法

c) 非常简单的线程安全类(线程安全堆栈或列表)的示例—它们都执行相同的操作—实现锁定/解锁方法,这些方法进入/离开关键部分,并在锁定时返回实际的堆栈/列表指针

现在我正在寻找解释应该保护代码的哪些部分

可以是代码形式;)但请不要再向我提供一个“使用同步更新progressbar”…;)


谢谢大家!

你在问一个非常普遍的问题的具体答案

基本上,除了UI操作之外,您还应该保护每个共享内存/资源访问,以避免两个可能相互竞争的线程:

  • 读取不一致内存
  • 同时写入内存
  • 尝试从多个线程同时使用同一资源。。。直到资源是线程安全的
一般来说,我认为任何其他操作线程都是安全的,包括访问非共享内存或不共享对象的操作。 例如,考虑这个对象:

type
  TThrdExample = class
  private
    FValue: Integer;
  public
    procedure Inc;
    procedure Dec;
    function Value: Integer;
    procedure ThreadInc;
    procedure ThreadDec;
    function ThreadValue: Integer;
  end;

ThreadVar
  ThreadValue: Integer;
Inc、Dec和Value是在FValue字段上操作的方法。在使用某种同步机制保护这些方法之前,它们不是线程安全的。它可以是值函数的MultipleReaderExclusiveWriterInchronizer,Inc和Dec方法的CriticalSection

thRead和TyReDeC方法在THealValk变量上操作,这被定义为SuthEdvar,因此我认为它是安全的,因为它们访问的内存不是线程之间共享的…来自不同线程的每个调用将访问不同的内存地址

如果您知道,通过设计,类只能在一个线程中使用,或者在其他同步机制内使用,您可以自由地考虑线程安全的设计。 如果你想要更具体的答案,我建议你试着问一个更具体的问题

致以最良好的祝愿


<>强>编辑:< /强>也许有人说整型字段是一个坏例子,因为您可以考虑在英特尔/ Windows上使用整数运算原子,因此不需要保护它。但我希望您能理解。

您误解了TThread.Synchronize方法

Synchronize和TThread.Queue方法在主(GUI)线程的上下文中执行受保护的代码。这就是为什么您应该使用Syncronize或Queue来更新GUI控件(如progressbar)——通常只有主线程应该访问GUI控件


关键部分是不同的-受保护的代码是在获取关键部分的线程的上下文中执行的,在前一个线程释放它之前,不允许其他线程获取关键部分。

如果需要以原子方式更新某组对象,则使用关键部分。这意味着,它们必须在任何时候都已完全更新或尚未更新。在过渡状态下,它们绝不能被访问

例如,对于简单的整数读取/写入,情况并非如此。读取整数的操作以及写入它的操作已经是原子化的:您不能在处理器的中间读取整数,它是半更新的。它要么是旧值,要么是新值

但是,如果您想以原子方式递增整数,您必须同时执行三个操作,而不是一个操作:将旧值读入处理器的缓存,递增,然后将其写回内存。每个操作都是原子的,但三个操作加在一起就不是了

一个线程可能读取旧值(比如200),在缓存中将其递增5,同时另一个线程也可能读取该值(仍然是200)。然后,第一个线程写回205,而第二个线程将其缓存值200增加到203,并写回203,覆盖205。两个增量(+5和+3)的结果应该是208,但由于操作的非原子性,它是203

因此,在以下情况下使用临界截面:

  • 一个变量、一组变量或任何资源是从多个线程使用的,需要进行原子更新
  • 它本身不是原子的(例如,调用一个由函数体内部的关键部分保护的函数,已经是一个原子操作了)

  • 阅读本文档


    如果使用消息传递在线程之间进行通信,那么基本上可以完全忽略同步原语,因为每个线程只访问其内部结构和消息本身。本质上,这是一种比使用同步原语更简单、更具可扩展性的体系结构。

    我不想得到更具体的答案。事实上,我甚至在寻找更一般的。我需要学习很多关于线程的知识,我正在寻找一个好的“切入点”;)特别是因为我从第6版开始使用Delphi,从未见过ThreadVar语句…@migajek:不,第三点是正确的。jachguate是说两个线程可能会做什么