Delphi系统单元中的TMonitor有什么好处?

Delphi系统单元中的TMonitor有什么好处?,delphi,delphi-2010,delphi-2009,delphi-xe,tmonitor,Delphi,Delphi 2010,Delphi 2009,Delphi Xe,Tmonitor,在阅读了文章和“德尔福的甲骨文”(艾伦·鲍尔)之后,我只了解甲骨文:) 这篇文章提到了Delphi并行库(DPL)、无锁数据结构和(这篇Wikipedia文章转发到“”),然后介绍了线程同步的新方法,并描述了它的一些方法 有没有介绍文章和例子来说明何时以及如何使用这种Delphi记录类型?有一些在线文章 TCriticalSection和TMonitor之间的主要区别是什么 使用Pulse和pulsell方法可以做什么 它是否有对应的语言,例如C#或Java语言 RTL或VCL中是否有使用此类

在阅读了文章和“德尔福的甲骨文”(艾伦·鲍尔)之后,我只了解甲骨文:)

这篇文章提到了Delphi并行库(DPL)、无锁数据结构和(这篇Wikipedia文章转发到“”),然后介绍了线程同步的新方法,并描述了它的一些方法

有没有介绍文章和例子来说明何时以及如何使用这种Delphi记录类型?有一些在线文章

  • TCriticalSection和TMonitor之间的主要区别是什么

  • 使用
    Pulse
    pulsell
    方法可以做什么

  • 它是否有对应的语言,例如C#或Java语言

  • RTL或VCL中是否有使用此类型的代码(因此可以作为示例)


更新:这篇文章解释说Delphi中的每个对象现在都可以使用一个TMonitor记录来锁定,每个实例需要额外4个字节

TMonitor的实现类似于:

每个对象都有一个内在锁 根据惯例,一种 需要独占和 一致访问对象的 字段必须获取对象的 在访问它们之前,先进行内部锁定, 然后释放内部锁 当他们结束的时候

,在Delphi中似乎与Java编程语言中的对应。如果我错了,请更正:)


更新2:使用
TMonitor.Wait
TMonitor.pulsell
的生产者/消费者应用程序的示例代码,基于中关于保护方法的文章(欢迎评论):

这种应用程序共享数据 在两个线程之间:生产者, 这将创建数据,并且 消费者,这对它有作用。 这两个线程使用 共享对象。协调是 要点:消费者线程必须 不尝试检索数据 在生产者线程完成之前 交付了它,还有制作人线程 不得尝试传递新数据 如果消费者尚未检索到 旧数据

在本例中,数据是一系列文本消息,通过Drop类型的对象共享:

program TMonitorTest;

// based on example code at http://download.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;

type
  Drop = class(TObject)
  private
    // Message sent from producer to consumer.
    Msg: string;
    // True if consumer should wait for producer to send message, false
    // if producer should wait for consumer to retrieve message.
    Empty: Boolean;
  public
    constructor Create;
    function Take: string;
    procedure Put(AMessage: string);
  end;

  Producer = class(TThread)
  private
    FDrop: Drop;
  public
    constructor Create(ADrop: Drop);
    procedure Execute; override;
  end;

  Consumer = class(TThread)
  private
    FDrop: Drop;
  public
    constructor Create(ADrop: Drop);
    procedure Execute; override;
  end;

{ Drop }

constructor Drop.Create;
begin
  Empty := True;
end;

function Drop.Take: string;
begin
  TMonitor.Enter(Self);
  try
    // Wait until message is available.
    while Empty do
    begin
      TMonitor.Wait(Self, INFINITE);
    end;
    // Toggle status.
    Empty := True;
    // Notify producer that status has changed.
    TMonitor.PulseAll(Self);
    Result := Msg;
  finally
    TMonitor.Exit(Self);
  end;
end;

procedure Drop.Put(AMessage: string);
begin
  TMonitor.Enter(Self);
  try
    // Wait until message has been retrieved.
    while not Empty do
    begin
      TMonitor.Wait(Self, INFINITE);
    end;
    // Toggle status.
    Empty := False;
    // Store message.
    Msg := AMessage;
    // Notify consumer that status has changed.
    TMonitor.PulseAll(Self);
  finally
    TMonitor.Exit(Self);
  end;
end;

{ Producer }

constructor Producer.Create(ADrop: Drop);
begin
  FDrop := ADrop;
  inherited Create(False);
end;

procedure Producer.Execute;
var
  Msgs: array of string;
  I: Integer;
begin
  SetLength(Msgs, 4);
  Msgs[0] := 'Mares eat oats';
  Msgs[1] := 'Does eat oats';
  Msgs[2] := 'Little lambs eat ivy';
  Msgs[3] := 'A kid will eat ivy too';
  for I := 0 to Length(Msgs) - 1 do
  begin
    FDrop.Put(Msgs[I]);
    Sleep(Random(5000));
  end;
  FDrop.Put('DONE');
end;

{ Consumer }

constructor Consumer.Create(ADrop: Drop);
begin
  FDrop := ADrop;
  inherited Create(False);
end;

procedure Consumer.Execute;
var
  Msg: string;
begin
  repeat
    Msg := FDrop.Take;
    WriteLn('Received: ' + Msg);
    Sleep(Random(5000));
  until Msg = 'DONE';
end;

var
  ADrop: Drop;
begin
  Randomize;
  ADrop := Drop.Create;
  Producer.Create(ADrop);
  Consumer.Create(ADrop);
  ReadLn;
end.
现在,这正如预期的那样工作,但是有一个细节我可以改进:不是用
TMonitor.Enter(Self)锁定整个Drop实例,我可以选择细粒度的锁定方法,带有一个(私有)“FLock”字段,仅在
TMonitor.Enter(FLock)的Put和Take方法中使用它

如果将代码与Java版本进行比较,我还注意到Delphi中没有可用于取消调用
Sleep
InterruptedException

更新3:2011年5月,一份关于OmniThreadLibrary的报告提出了TMonitor实现中可能存在的错误。它似乎与中的一个条目有关。评论提到一个补丁是由一个Delphi用户提供的,但是它不可见


更新4:2013年的一项研究表明,尽管TMonitor是“公平的”,但其性能比临界区差。

TMonitor将临界区(或简单互斥)的概念与条件变量结合起来。您可以在此处了解什么是“监视器”:

在任何需要使用关键部分的地方,都可以使用监视器。您可以简单地创建一个ToObject实例,然后使用它,而不是声明TCriticalSection

TMonitor.Enter(FLock);
try
  // protected code
finally
  TMonitor.Exit(FLock);
end;

其中FLock是任何对象实例。通常,我只是创建一个TObject:

FLock := TObject.Create;

FLock是任何对象实例。它可以只是一个简单的TObject实例。FLock:=TObject.Create;还是不够。您已经演示了如何使用TMonitor模拟关键部分,但请确保这不是TMonitor设计的真正问题。您能给出一个更有趣的代码示例吗?您可能还想添加一些信息,说明为什么您选择在VCL中添加通常被人诟病的锁定任何对象的功能。例如,Mjustin,我不会说
FLock
是本例中的监视器。它有一个监视器,我们用它来保护一些代码。如果我们已经有了其他的TObject,我们可能会使用它的监视器,而不是仅仅为了这个目的创建一个新对象。这不一定是多个线程正在使用的对象(这是try finally部分中使用的内容),但要想获得任何好处,其他线程需要了解
FLock
,以便它们可以在同一个对象上等待。(就像一个关键部分一样,如果只有一个线程使用它,那么它是无用的。)@Rob:Wikipedia将Monitor定义为“一个多线程安全使用的对象”——在本例中,一个锁定对象(FLock)用于保护不同对象中的代码。文章mghielinks说,在对象上创建全局锁是个坏主意(“为什么锁(this){…}坏?”)。其他线程不需要“知道”(有权访问)FLock,FLock可以是一个私有实例变量,只在一个同步方法中使用。
TMonitor
有严重的错误,这些错误最终在XE2 upd 4中得到纠正。在
TThreadedQueue
中使用TMonitor可能会显示错误。有关更多信息,请参阅。