什么是Delphi System单元中的TMonitor有用?

时间:2010-07-31 09:41:11

标签: delphi delphi-2010 delphi-2009 delphi-xe tmonitor

在阅读了“Delphi的甲骨文”(Allen Bauer)的文章"Simmering Unicode, bring DPL to a boil""Simmering Unicode, bring DPL to a boil (Part 2)"之后,Oracle就是我所理解的:)

文章提到Delphi Parallel Library(DPL),锁定免费数据结构,mutual exclusion lockscondition variables(这篇维基百科文章转发给'Monitor (synchronization)',然后介绍新的{{} 3}}用于线程同步并描述它的一些方法。

是否有介绍文章,其中的示例显示了何时以及如何使用此Delphi记录类型?网上有一些TMonitor record type

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

  • 我可以使用PulsePulseAll方法做些什么?

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

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


更新:文章documentation解释说现在可以使用TMonitor记录锁定Delphi中的每个对象,每个实例的额外四个字节的价格。

看起来TMonitor的实现类似于Why Has the Size of TObject Doubled In Delphi 2009?

  

每个对象都有一个内在锁   与之相关联。按惯例,a   需要排他性的线程   对对象的一致访问   字段必须获取对象的   在访问它们之前的内部锁定   然后释放内在锁   什么时候用它们完成。

Delphi中的

Intrinsic Locks in the Java languageWaitPulse似乎是Java编程语言中PulseAllwait()notify()的对应部分。如果我错了,请纠正我:)


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

  

这种应用程序共享数据   两个线程之间:生产者,   创建数据,和   消费者,用它做点什么。   两个线程使用a进行通信   共享对象。协调是   必要的:消费者线程必须   不要尝试检索数据   在生产者线程之前   交付它,以及生产者线程   不得试图提供新数据   如果消费者没有检索到   旧数据。

在此示例中,数据是一系列文本消息,通过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 and Take方法中使用它。

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

更新3 :2011年5月,关于OmniThreadLibrary的Java(tm) tutorials提出了TMonitor实施中可能存在的错误。它似乎与blog entry中的条目有关。评论中提到了一个由Delphi用户提供的补丁,但它不可见。

更新4 :2013年Quality Central显示虽然TMonitor“公平”,但其性能却比关键部分差。

1 个答案:

答案 0 :(得分:8)

TMonitor结合了关键部分(或简单的互斥锁)的概念以及条件变量。您可以在这里阅读“监视器”的内容:http://en.wikipedia.org/wiki/Monitor_%28synchronization%29

任何地方你都会使用一个关键部分,你可以使用一个监视器。您可以简单地创建一个TObject实例,然后使用它来代替声明TCriticalSection。

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

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

FLock := TObject.Create;