Delphi系统中TMonitor是什么? [英] What is TMonitor in Delphi System unit good for?

查看:1776
本文介绍了Delphi系统中TMonitor是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读文章后,炖炖Unicode,让DPL沸腾Simmering Unicode,使DPL沸腾(第2部分)

After reading the articles "Simmering Unicode, bring DPL to a boil" and "Simmering Unicode, bring DPL to a boil (Part 2)" of "The Oracle at Delphi" (Allen Bauer), Oracle is all I understand :)

文章提到Delphi并行库(DPL),锁定自由数据结构,互斥锁条件变量(本维基百科文章转发给监视(同步),然后介绍新的 TMonitor记录类型< a>用于线程同步并进行描述我的方法。

The article mentions Delphi Parallel Library (DPL), lock free data structures, mutual exclusion locks and condition variables (this Wikipedia article forwards to 'Monitor (synchronization)', and then introduces the new TMonitor record type for thread synchronization and describes some of its methods.

是否有介绍文章与示例显示何时以及如何使用这种Delphi记录类型?在线有一些文档

Are there introduction articles with examples which show when and how this Delphi record type can be used? There is some documentation online.


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

  • What is the main difference between TCriticalSection and TMonitor?

我可以使用 Pulse PulseAll 方法?

是否有在C#或Java语言中的一个例子?

Does it have a counterpart for example in C# or the Java language?

RTL或VCL中是否存在使用此类型的代码(因此可以作为例如)

Is there any code in the RTL or the VCL which uses this type (so it could serve as an example)?

更新:文章为什么TObject的大小在Delphi 2009中翻倍?解释说,Delphi中的每个对象现在都可以使用TMonitor记录锁定,每个实例的价格为四个额外的字节。

Update: the article Why Has the Size of TObject Doubled In Delphi 2009? explains that every object in Delphi now can be locked using a TMonitor record, at the price of four extra bytes per instance.

看起来TMonitor类似于 Java语言中的固有锁

It looks like TMonitor is implemented similar to 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.

等待 Pulse 和Delphi中的 PulseAll 似乎是对应的 wait() notify() notifyAll( )的Java编程语言。更正2:生产者/消费者应用程序的示例代码

Wait, Pulse and PulseAll in Delphi seem to be counterparts of wait(), notify() and notifyAll() in the Java programming language. Correct me if I am wrong :)

使用 TMonitor.Wait TMonitor.PulseAll ,根据关于 Java(tm)教程(欢迎评论):

Update 2: Example code for a Producer/Consumer application using TMonitor.Wait and TMonitor.PulseAll, based on an article about guarded methods in the Java(tm) tutorials (comments are welcome):


这种应用程序在两个线程之间共享数据
:生产者,
创建数据,
消费者,这与它做了一些事情。
两个线程使用
共享对象进行通信。协调是
基本:消费者线程必须
在生产者线程
发送之前不尝试检索数据
,生产者线程
不得尝试如果消费者没有检索到
旧数据,则会传送新数据

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类型的对象共享:

In this example, the data is a series of text messages, which are shared through an object of type 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); 删除实例,我可以选择一个细粒度的锁定方法,使用(私人)FLock字段,仅在Put并通过 TMonitor.Enter(FLock); 获取方法。

Now this works as expected, however there is a detail which I could improve: instead of locking the whole Drop instance with TMonitor.Enter(Self);, I could choose a fine-grained locking approach, with a (private) "FLock" field, using it only in the Put and Take methods by TMonitor.Enter(FLock);.

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

If I compare the code with the Java version, I also notice that there is no InterruptedException in Delphi which can be used to cancel a call of Sleep.

更新3 :2011年5月,一个博客条目在TMonitor实现中提出了一个可能的错误。它似乎与 Quality Central 中的条目有关。评论提到修补程序是由Delphi用户提供的,但不可见。

Update 3: in May 2011, a blog entry about the OmniThreadLibrary presented a possible bug in the TMonitor implementation. It seems to be related to an entry in Quality Central. The comments mention a patch has been provided by a Delphi user, but it is not visible.

更新4 :A blog post 在2013年显示,虽然TMonitor是公平的,其表现比

Update 4: A blog post in 2013 showed that while TMonitor is 'fair', its performance is worse than that of a critical section.

推荐答案

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

TMonitor combines the notion of a critical section (or a simple mutex) along with a condition variable. You can read about what a "monitor" is here: http://en.wikipedia.org/wiki/Monitor_%28synchronization%29.

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

Anyplace you would use a critical section, you can use a monitor. Instead of declaring a TCriticalSection, you can simple create a TObject instance and then use that.

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

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

Where FLock is any object instance. Normally, I just create a TObject:

FLock := TObject.Create;

这篇关于Delphi系统中TMonitor是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆