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

mjn*_*mjn 31 delphi delphi-2009 delphi-2010 tmonitor delphi-xe

在阅读了文章"Simmering Unicode,让DPL沸腾""Simmering Unicode,让DPL沸腾(第2部分)"的"Oracle Delphi"(Allen Bauer)之后,Oracle就是我理解的全部:)

文章提到了Delphi Parallel Library(DPL),锁定免费数据结构,互斥锁条件变量(这篇维基百科文章转发到' Monitor(同步) ',然后介绍了用于线程同步的新TMonitor记录类型并描述了它的一些方法.

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

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

  • 我能做些什么与PulsePulseAll方法呢?

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

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


更新:文章为什么在Delphi 2009中TObject的大小翻了一番?解释说现在可以使用TMonitor记录锁定Delphi中的每个对象,每个实例需要额外四个字节.

看起来TMonitor的实现类似于Java语言中的Intrinsic Locks:

每个对象都有一个与之关联的内在锁.按照惯例,需要对对象字段进行独占和一致访问的线程必须在访问对象之前获取对象的内部锁,然后在完成它们时释放内部锁.

等待,Delphi中的PulsePulseAll似乎是Java编程语言中wait(),notify()notifyAll()的对应物.如果我错了,请纠正我:)


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

这种应用程序在两个线程之间共享数据:生成器,创建数据,以及使用它的消费者.两个线程使用共享对象进行通信.协调是必不可少的:消费者线程不得在生产者线程交付之前尝试检索数据,并且如果消费者未检索旧数据,则生产者线程不得尝试传递新数据.

在此示例中,数据是一系列文本消息,通过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.
Run Code Online (Sandbox Code Playgroud)

现在这可以按预期工作,但是我可以改进一个细节:TMonitor.Enter(Self);我可以选择一个细粒度的锁定方法,使用(私有)"FLock"字段,仅使用它,而不是锁定整个Drop实例.放置和采取方法TMonitor.Enter(FLock);.

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

更新3:2011年5月,关于OmniThreadLibrary 的博客文章提出了TMonitor实现中可能存在的错误.这似乎与Quality Central的一个条目有关.评论中提到了一个由Delphi用户提供的补丁,但它不可见.

更新4:2013年的一篇博文显示,虽然TMonitor"公平",但其性能却比关键部分的性能差.

All*_*uer 8

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

无论你在哪个地方使用临界区,都可以使用监视器.您可以简单地创建一个TObject实例,然后使用它来代替声明TCriticalSection.

TMonitor.Enter(FLock);
try
  // protected code
finally
  TMonitor.Exit(FLock);
end;
Run Code Online (Sandbox Code Playgroud)

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

FLock := TObject.Create;
Run Code Online (Sandbox Code Playgroud)

  • 仍然不够.您已经展示了如何使用TMonitor模拟关键部分,但确定这不是TMonitor设计的真正问题.你能给出一个更有趣的代码示例吗? (5认同)
  • 您可能还想添加一些信息,为什么您选择向VCL添加锁定任何对象的一般受到谴责的能力.例如,参见http://stackoverflow.com/questions/251391/why-is-lockthis-bad. (2认同)