阅读文章 “Simmering Unicode,bring DPL to a boil”和 “Simmering Unicode,bring DPL to a boil (Part 2)”的“Oracle在Delphi”(艾伦鲍尔),Oracle是我所理解的:)

文章提到Delphi并行库(dpl),无锁数据结构,mutual exclusion locks和condition 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,Pulse和PulseAll似乎是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;

什么是德尔福系统单元TMonitor有好处?的更多相关文章

  1. HTML5 WebSocket实现点对点聊天的示例代码

    这篇文章主要介绍了HTML5 WebSocket实现点对点聊天的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

  3. ios – 在Swift中将输入字段字符串转换为Int

    所以我非常擅长制作APP广告Swift,我试图在文本字段中做一些非常简单的输入,取值,然后将它们用作Int进行某些计算.但是’vardistance’有些东西不正确它是导致错误的最后一行代码.它说致命错误:无法解开Optional.None解决方法在你的例子中,距离是一个Int?否则称为可选的Int..toInt()返回Int?因为从String到Int的转换可能失败.请参阅以下示例:

  4. 如何在iOS中检测文本(字符串)语言?

    例如,给定以下字符串:我想检测每个声明的字符串中使用的语言.让我们假设已实现函数的签名是:如果没有检测到语言,则返回可选字符串.因此,适当的结果将是:有一个简单的方法来实现它吗?

  5. xamarin – 崩溃在AccountStore.Create().保存(e.Account,“);

    在Xamarin.Forms示例TodoAwsAuth中https://developer.xamarin.com/guides/xamarin-forms/web-services/authentication/oauth/成功登录后,在aOnAuthenticationCompleted事件中,应用程序在尝试保存到Xamarin.Auth时崩溃错误说不能对钥匙串说期待着寻求帮助.解决方法看看你

  6. ios – 将视频分享到Facebook

    我正在编写一个简单的测试应用程序,用于将视频从iOS上传到Facebook.由于FacebookSDK的所有文档都在Objective-C中,因此我发现很难在线找到有关如何使用Swift执行此操作的示例/教程.到目前为止我有这个在我的UI上放置一个共享按钮,但它看起来已禁用,从我读到的这是因为没有内容设置,但我看不出这是怎么可能的.我的getVideoURL()函数返回一个NSURL,它肯定包含视

  7. xcode – 错误“线程1:断点2.1”

    我正在研究RESTAPI管理器.这是一个错误,我无法解决它.我得到的错误在下面突出显示.当我打电话给这个班级获取资源时:我评论的线打印:Thread1:breakpoint2.1我需要修复错误的建议.任何建议都非常感谢解决方法您可能在不注意的情况下意外设置了断点.单击并拖动代表断路器外部断点的蓝色刻度线以将其擦除.

  8. ios – 更改导航栏标题swift中的字符间距

    类型的值有人可以帮我这个或建议一种不同的方式来改变swift中导航栏标题中的字符间距吗?解决方法您无法直接设置属性字符串.你可以通过替换titleView来做一个技巧

  9. ios – 如何从变量访问属性或方法?

    是否可以使用变量作为Swift中方法或属性的名称来访问方法或属性?在PHP中,您可以使用$object->{$variable}.例如编辑:这是我正在使用的实际代码:解决方法你可以做到,但不能使用“纯粹的”Swift.Swift的重点是防止这种危险的动态属性访问.你必须使用Cocoa的Key-ValueCoding功能:非常方便,它完全穿过你要穿过的字符串到属性名称的桥,但要注意:这里是龙.

  10. ios – 如果我将自动释放的对象桥接到Core Foundation,我必须使用__bridge或__bridge_retained吗?

    ARC迁移工具遇到了这个问题:特别是,它不确定它是否应该执行__bridge或__bridge_retained.而我也是.-fileURLWithPath返回一个自动释放的对象,在这个地方我不是fileURL的所有者.但与此同时,该对象的保留计数至少为1.我敢打赌,这只能用__bridge来完成.解决方法您只想为此使用常规__bridge强制转换.仅当您想要管理强制转换CF对象的生命周期时,才会使用__bridge_retained.例如:所以__bridge_retained确实告诉编译器你有一个AR

随机推荐

  1. delphi – 主窗口按进程名称处理

    DelphiXe,Win7x64如何从进程名称(exe文件的完整路径)获取主窗口句柄,或至少一个类或窗口名称(如果该进程只有一个窗口).例:解决方法我同意Petesh的说法,你需要枚举顶级窗口并检查创建它的进程的模块文件名.为了帮助您开始枚举顶级窗口,这是一个delphi实现.首先,当你回调给你时,你需要一些与EnumWindows方法通信的方式.为此声明一条记录,该记录将保存您要查找的模块的文件

  2. 如何在Delphi中纯粹通过RTTI信息(即不使用任何实际对象实例)获取TObjectList的子项类型?

    我正在使用RTTI实现用于流式传输任意Delphi对象的通用代码,并且为了使其工作(更具体地说,为了使加载部分工作),我需要以某种方式获得TObjectList的子项类型<T>不使用任何实际对象实例的字段.要求不使用任何实际对象实例的明显原因是,在从流加载对象的情况下(仅基于要加载的对象的类类型的知识),我将不会有任何实例在加载完成之前完全可用–我宁愿只能访问相关类的纯RTTI数据.我希望能

  3. inno-setup – Inno Setup – 安装程序背景图片

    图像作为安装程序背景如何用inno5.5.9做到这一点?

  4. inno-setup – Inno Setup – 如何添加多个arc文件进行解压缩?

    使用InnoSetup解压缩弧文件.我希望有可能解压缩多个arc文件以从组件选择中安装文件(例如).但仍然显示所有提取的整体进度条.这可能吗?的回答的修改预备是相同的,参考其他答案.在ExtractArc中,为要提取的每个存档调用AddArchive.

  5. delphi – 如何在DataSet的帮助下在TAdvStringGrid中显示数据库中的BLOB图像

    解决方法CreateBlobStream正在创建一个TStream对象,而不是TMemoryStream.由于您不想将JPG写入数据库,因此应使用bmRead而不是bmReadWrite.我不习惯sqlite,但你必须确保使用合适的二进制日期类型.为了确保存储的图像真的是JPG,您应该编写JPG以进行测试,例如:

  6. inno-setup – 在Inno Setup的Code部分下载程序后运行程序

    如何运行我通过Internet下载的应用程序,在代码部分中使用,并等待该应用程序完成运行.我有,使用InnoTools下载程序,下载这两个文件,我想,在第二个完成下载后运行该下载,或jdk-8u111-windows-x64.exe,然后继续安装.解决方法使用其他下载插件,而不是ITD(请参阅下面的原因).例如,InnoDownloadPlugin.当您包含idp.iss时,它定义了一个全局IDP

  7. progress-bar – Inno Setup Run部分的简单进度页面

    我的安装程序非常简单,它基本上是:>欢迎页面>进展页面>最终页面欢迎页面和最终页面是标准页面.在Progress页面,我正在静默安装一堆其他程序.实际的脚本是在[Run]部分中安装每个程序.问题是酒吧达到100%然后停留在那里.我只能更改消息文本.我想要实现的是使用Pascal脚本显示进度,例如:这样我就可以显示更准确的进度条.这就是我所拥有的:问题是,当我构建安装程序时,它不显示欢迎页面.我做错了什么?

  8. delphi – 如何使“显示/隐藏桌面图标”设置生效?

    下面的代码调用SHGetSetSettings函数来隐藏桌面图标但它只是从视图菜单中取消选中“显示桌面图标”.我打电话给SHChangeNotify;更新桌面,但这不起作用?解决方法isa,要刷新桌面,您可以将F5键发送到progman窗口隐藏桌面图标的另一种方法是再次显示

  9. inno-setup – Inno Setup – 避免显示子安装程序的文件名

    我试图使用InnoSetup–Howtohidecertainfilenameswhileinstalling?(FilenameLabel)的想法Theonlysuresolutionistoavoidinstallingthefiles,youdonotwanttoshow,usingthe[Files]section.Installthemusingacodeinstead.UsetheEx

  10. inno-setup – Inno Setup磁力链接下载实施

    我目前正在使用InnoDownloadPlugin为我的安装程序下载文件,这个问题最大的问题是faila正确下载文件.因为连接不良等诸多原因.我想添加一种替代方法来下载文件,因此用户可以选择是否需要常规方式或torrent方式.我知道我可以使用aria2c.exe应用程序(https://aria2.github.io/),有人可以帮我实现它的inno设置代码吗?我需要的是使用torrent(ar

返回
顶部