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

问题描述 投票:0回答:1

在阅读了“The Oracle at Delphi”(Allen Bauer)的“Simmering Unicode,bring DPL to a沸腾”“Simmering Unicode,bring DPL to a沸腾(第2部分)”后,Oracle就是我的全部明白了:)

文章提到了 Delphi 并行库(DPL)、无锁数据结构、互斥锁条件变量(这篇维基百科文章转发到“Monitor(同步)”,然后介绍了新的TMonitor记录类型) 用于线程同步并描述其一些方法。

是否有带有示例的介绍文章,说明何时以及如何使用此 Delphi 记录类型?网上有一些文档

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

  • 我可以使用

    Pulse
    PulseAll
    方法做什么?

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

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


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

看起来TMonitor的实现类似于Java语言中的内在锁:

每个对象都有一个内在锁 与之相关。按照惯例,一个 需要独占的线程 对对象的一致访问 fields 必须获取对象的 访问它们之前的内在锁, 然后释放内在锁 当他们完成时。

Delphi 中的

WaitPulsePulseAll 似乎与 Java 编程语言中的 wait()notify()notifyAll() 相对应。如果我错了请纠正我:)


更新 2:使用 TMonitor.Wait

TMonitor.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.

现在这按预期工作,但是有一个细节我可以改进:我可以选择一种细粒度的锁定方法,使用(私有)“FLock”字段,而不是使用

TMonitor.Enter(Self);
锁定整个 Drop 实例仅在 Put 和 Take 方法中通过
TMonitor.Enter(FLock);

如果我将代码与 Java 版本进行比较,我还注意到 Delphi 中没有

InterruptedException
可以用来取消
Sleep
的调用。

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

更新 4:2013 年的一篇博客文章表明,虽然 TMonitor 是“公平”的,但它的性能比关键部分差。

delphi delphi-2010 delphi-2009 delphi-xe tmonitor
1个回答
13
投票

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;
© www.soinside.com 2019 - 2024. All rights reserved.