什么是德尔福系统单元TMonitor有好处?

前端之家收集整理的这篇文章主要介绍了什么是德尔福系统单元TMonitor有好处?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
阅读文章 “Simmering Unicode,bring DPL to a boil”“Simmering Unicode,bring DPL to a boil (Part 2)”的“Oracle在Delphi”(艾伦鲍尔),Oracle是我所理解的:)

文章提到Delphi并行库(DPL),无锁数据结构,mutual exclusion lockscondition variables(这篇维基百科文章转发到“Monitor (synchronization)”,然后介绍了新的TMonitor record type线程同步,并描述了它的一些方法

有没有介绍文章与示例,显示何时和如何这个Delphi记录类型可以使用?有一些documentation在线。

> TCriticalSection和TMonitor之间的主要区别是什么?
>我可以用Pulse和PulseAllmethods做什么?
>它有一个对应的例如在C#或Java语言?
>在RTL或VCL中是否有使用此类型的代码(因此它可以作为示例)?

更新:文章Why Has the Size of TObject Doubled In Delphi 2009?解释说,现在可以使用TMonitor记录锁定Delphi中的每个对象,每个实例的价格为4个额外字节。

看起来TMonitor的实现类似于Intrinsic Locks in the Java language

Every object has an intrinsic lock
associated with it. By convention,a
thread that needs exclusive and
consistent access to an object’s
fields has to acquire the object’s
intrinsic lock before accessing them,
and then release the intrinsic lock
when it’s done with them.

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

更新2:使用TMonitor.Wait和TMonitor.PulseAll的生产者/消费者应用程序的示例代码,基于Java(tm) tutorials中有关保护方法文章(欢迎提出意见):

This kind of application shares data
between two threads: the producer,
that creates the data,and the
consumer,that does something with it.
The two threads communicate using a
shared object. Coordination is
essential: the consumer thread must
not attempt to retrieve the data
before the producer thread has
delivered it,and the producer thread
must not attempt to deliver new data
if the consumer hasn’t retrieved the
old data.

在此示例中,数据是一系列文本消息,通过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.

现在这个工作作为预期,但有一个细节,我可以改进:而不是锁定整个Drop实例与TMonitor.Enter(Self);我可以选择一个细粒度锁定方法,与(私人)“FLock”字段,仅在通过TMonitor.Enter(FLock);在Put和Take方法中使用它。

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

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

更新4:2013年blog post显示,虽然TMonitor是“公平”,其性能比关键部分差。

解决方法

TMonitor将关键部分(或简单互斥体)的概念与条件变量结合在一起。你可以阅读这里的“监视器”: http://en.wikipedia.org/wiki/Monitor_%28synchronization%29

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

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

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

FLock := TObject.Create;

猜你在找的Delphi相关文章