iTask - 将参数值传递给匿名过程

2023-12-10

我需要创建一定数量的 iTask 来执行动态数组和记录中其他字段的操作。每个 iTask 都在该数组的特定部分中运行。该数组是记录中的一个字段,它作为 var 参数传递给 iTask。

数组字段中的操作进展顺利,但其他记录字段在所有任务完成工作后不会返回任何值。我在另一个问题上得到了 Dalija 的帮助,该问题仅在数组上运行并且它有效,但现在我在其他领域遇到了麻烦。

这是我的代码:

program ProjectTest;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  System.Threading;

type
  myrec = record
    vet: array of integer;
    total: integer;
    average: integer;
  end;

// (1) ===> here is the major procedure that populates the dyn. array and
// calculates other two fields  :  myrec.total  and myrec.avg

procedure ProcA(const pin, pfin: integer; var Prec: myrec);
var
  vind: integer;
begin
  for vind := pin to pfin do
    begin
      Prec.vet[vind] := vind * 10;
      Prec.total := Prec.total + Prec.vet[vind];        // sum all array values
    end;
  Prec.average := Trunc(Prec.total / Length(Prec.vet)); // calculates the average

end;

// (2)  Here iTask is created and calls ProcA

function CreateTask(first, last: integer; var Pmyrec: myrec): ITask;

var
  mylocalrec: myrec;

begin
  mylocalrec := Pmyrec;
  Result := TTask.Create(
    procedure
    begin
      ProcA(first, last, mylocalrec)
    end);
end;

procedure Test;
var
  Recarray: myrec;
  Ptasks: array of ITask;
  vind, indtask, vslice: integer;
  vfirst, vlast, vthreads, vsize: integer;
begin

  vthreads := 4;
  vsize := 16;

  SetLength(Ptasks, vthreads);
  SetLength(Recarray.vet, vsize);

  // Initialize the array , just to check after iTask execution
  for vind := low(Recarray.vet) to high(Recarray.vet) do
    Recarray.vet[vind] := -33;

  // initialize the sum and average field just to check after iTask execution
  Recarray.total := -1;
  Recarray.average := -2;

  // portion of array to scan for each iTask
  vslice := Length(Recarray.vet) div vthreads;

  for indtask := low(Ptasks) to high(Ptasks) do
    begin
      vfirst := indtask * vslice;
      vlast := (indtask + 1) * vslice - 1;

      if (Length(Recarray.vet) mod vthreads <> 0) and (indtask = high(Ptasks)) then vlast := high(Recarray.vet);

      Ptasks[indtask] := CreateTask(vfirst, vlast, Recarray);
    end;

  // Starting all Tasks
  for indtask := low(Ptasks) to high(Ptasks) do
    Ptasks[indtask].Start;

  // Waits for all Tasks been concluded
  TTask.WaitForAll(Ptasks);

  // (3) Here it is listed the array contents and it is ok
  for vind := low(Recarray.vet) to high(Recarray.vet) do
      Writeln(' Array position  : ' + Format('%.3d', [vind]) + '   content  : ' + Recarray.vet[vind].tostring);

  Writeln(' =========================================================');

// (4) Here is is listed fields recarray.total and recarray.avg and they were not
// processed inside the iTask .    I expected to see the computed values for those fields

  Writeln(' Array sum   : ' + Format('%.0d', [Recarray.total]) + '    Array average   : ' + Format('%5.2n', [Recarray.average * 1.0]));

end;

begin
  Test;
  Readln;
end.

输出是:

 Array position  : 000   content  : 0
 Array position  : 001   content  : 10
 Array position  : 002   content  : 20
 Array position  : 003   content  : 30
 Array position  : 004   content  : 40
 Array position  : 005   content  : 50
 Array position  : 006   content  : 60
 Array position  : 007   content  : 70
 Array position  : 008   content  : 80
 Array position  : 009   content  : 90
 Array position  : 010   content  : 100
 Array position  : 011   content  : 110
 Array position  : 012   content  : 120
 Array position  : 013   content  : 130
 Array position  : 014   content  : 140
 Array position  : 015   content  : 150
 =========================================================
 Array sum   : -1    Array average   : -2,00

问题是:运行所有iTasks后,只有动态数组字段recarray.vet包含正确的值。田野recarray.total and recarray.average仍然包含 iTask 运行之前的初始值。

如何正确更新这些字段中的值,以便任务完成运行后它们将包含正确的值?


虽然您的代码似乎只有一个问题 - 如何用任务填充记录中的整数字段 - 当您解决这个问题时,您将遇到另一个问题 - 从多个线程读取和写入相同的内存位置。

1. 如何填充记录中的整数字段?

记录是值类型,动态数组是引用类型。这就是为什么您的代码可以更新数组中的值但无法更新记录中的值的原因。

让我们看看这里发生了什么。

function CreateTask(first, last: integer; var pmyrec: myrec): ITask;
var
  mylocalrec: myrec;
begin
  mylocalrec := pmyrec;

Since mylocalrec and pmyrec是记录(值类型),它们的内容将占用两个不同的内存位置。以上作业将复制content of the pmyrec into mylocalrec.

这将相当于以下内容:

mylocalrec.vet := pmyrec.vet;
mylocalrec.total := pmyrec.total;
mylocalrec.average := pmyrec.average;

Since total and average也是值类型,它们的内容将被复制,从此时起,对这些整数字段中的任何一个进行任何更改mylocalrec不会对原来有任何影响pmyrec。这就是您的代码失败的原因。

为什么分配动态数组字段vet from pmyrec to mylocalrec works?

因为动态数组是引用类型 - 从一个变量到另一个变量的赋值仅复制引用(指针)的值,而不是实际内容。两个都vet变量将指向您开始运行任务之前分配的同一数组。

要解决上述问题,您必须传递一些引用类型而不是值类型。最简单的事情是声明记录指针类型并传递该类型。

type
  myrec = record
    vet: array of integer;
    total: integer;
    average: integer;
  end;

  pmyrec = ^myrec;


function CreateTask(first, last: integer; rec: pmyrec): ITask;
var
  mylocalrec: pmyrec;
begin
  mylocalrec := rec;
  Result := TTask.Create(
    procedure
    begin
      ProcA(first, last, mylocalrec^)
    end);
end;

...
Ptasks[indtask] := CreateTask(vfirst, vlast, @Recarray);

2. 如何解决线程问题?

解决原始问题后,您将遇到线程问题。从多个线程读取和写入同一内​​存位置是不安全的。您得到的结果可能不正确。虽然您可以运行代码数千次并且所有值可能都是正确的,但迟早您会遇到它们不正确的情况。

在您的情况下,填充动态数组是安全的,因为每个线程都在数组的不同部分上操作,并且在任务运行时不会重新分配数组(其大小不会更改)。这部分代码是线程安全的。

计算total and average不是线程安全的。

您必须将此类代码与主线程同步 - 在这种情况下,所有读取和写入都将从主线程完成,您将获得正确的结果。或者您必须在所有任务完成后运行此类代码。哪个更适合特定情况。

procedure ProcA(const pin, pfin: integer; prec: pmyrec);
var
  vind: integer;
  total: integer;
begin
  total := 0;
  for vind := pin to pfin do
    begin
      prec.vet[vind] := vind * 10;
      total := total + prec.vet[vind];        // sum all array values
    end;

  TThread.Synchronize(nil,
    procedure
    begin
      prec.total := prec.total + total;
      prec.average := Trunc(prec.total / Length(prec.vet)); // calculates the average
    end);
end;

然而,与任务内的主线程同步会导致死锁TTask.WaitForAll在您的情况下,该方法也从主线程运行。要解决该部分,您还必须运行整个Test来自另一个线程的方法。

  TTask.Run(
    procedure
    begin
      Test;
    end);

当我们将所有这些部分放在一起时,完整的代码将是:

program ProjectTest;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  System.Classes,
  System.Threading;

type
  myrec = record
    vet: array of integer;
    total: integer;
    average: integer;
  end;

  pmyrec = ^myrec;

// (1) ===> here is the major procedure that populates the dyn. array and
// calculates other two fields  :  myrec.total  and myrec.avg

procedure ProcA(const pin, pfin: integer; prec: pmyrec);
var
  vind: integer;
  total: integer;
begin
  total := 0;
  for vind := pin to pfin do
    begin
      prec.vet[vind] := vind * 10;
      total := total + prec.vet[vind];        // sum all array values
    end;

  TThread.Synchronize(nil,
    procedure
    begin
      prec.total := prec.total + total;
      prec.average := Trunc(prec.total / Length(prec.vet)); // calculates the average
    end);
end;

// (2)  Here iTask is created and calls ProcA

function CreateTask(first, last: integer; rec: pmyrec): ITask;
var
  mylocalrec: pmyrec;
begin
  mylocalrec := rec;
  Result := TTask.Create(
    procedure
    begin
      ProcA(first, last, mylocalrec);
    end);
end;

procedure Test;
var
  Recarray: myrec;
  Ptasks: array of ITask;
  vind, indtask, vslice: integer;
  vfirst, vlast, vthreads, vsize: integer;
begin

  vthreads := 4;
  vsize := 16;

  SetLength(Ptasks, vthreads);
  SetLength(Recarray.vet, vsize);

  // Initialize the array , just to check after iTask execution
  for vind := low(Recarray.vet) to high(Recarray.vet) do
    Recarray.vet[vind] := -33;

  // initialize the sum and average field just to check after iTask execution
  Recarray.total := -1;
  Recarray.average := -2;

  // portion of array to scan for each iTask
  vslice := Length(Recarray.vet) div vthreads;

  for indtask := low(Ptasks) to high(Ptasks) do
    begin
      vfirst := indtask * vslice;
      vlast := (indtask + 1) * vslice - 1;

      if (Length(Recarray.vet) mod vthreads <> 0) and (indtask = high(Ptasks)) then vlast := high(Recarray.vet);

      Ptasks[indtask] := CreateTask(vfirst, vlast, @Recarray);
    end;

  // Starting all Tasks
  for indtask := low(Ptasks) to high(Ptasks) do
    Ptasks[indtask].Start;

  // Waits for all Tasks been concluded
  TTask.WaitForAll(Ptasks);

  // (3) Here it is listed the array contents and it is ok
  for vind := low(Recarray.vet) to high(Recarray.vet) do
      Writeln(' Array position  : ' + Format('%.3d', [vind]) + '   content  : ' + Recarray.vet[vind].tostring);

  Writeln(' =========================================================');

// (4) Here is is listed fields recarray.total and recarray.avg and they were not
// processed inside the iTask .    I expected to see the computed values for those fields

  Writeln(' Array sum   : ' + Format('%.0d', [Recarray.total]) + '    Array average   : ' + Format('%5.2n', [Recarray.average * 1.0]));

end;

begin
  TTask.Run(
    procedure
    begin
      Test;
    end);
end.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iTask - 将参数值传递给匿名过程 的相关文章

  • JavaFX 多线程 - 连接线程不会更新 UI

    我正在尝试创建一个加载程序对话框 用户可以在其中知道程序正在加载所请求的内容并且程序正在按预期运行 但正因为如此 我需要join 解析器线程和之前继续主线程 这使得对话框空白 解析器任务 java public class ParserTa
  • Pthreads - 高内存使用率

    我正在用 C 编写一些东西 在 256Mb 系统上的 Linux 中创建大量 Pthread 我通常有 200Mb 的免费空间 当我使用少量线程运行该程序时 它可以工作 但是一旦我让它创建大约 100 个线程 它就会出现错误 因为系统内存不
  • 设置一个值来指示线程已完成安全吗?

    我想将一个耗时的进程委托给我的 C 程序中的一个单独的线程 使用 boost 库 我编写了如下代码 thrd new boost thread boost bind myclass mymethod this finished flag W
  • 通过不同的线程使用多个 ORB(多线程多 Orb 客户端应用程序) - 如何?

    This question is related to Is it possible to have several ORB objects in the same process https stackoverflow com quest
  • 当我们调用 Thread.start() 时真正发生了什么[重复]

    这个问题在这里已经有答案了 正如问题标题所说 我想知道当我们调用 Thread start 时内部发生了什么 以及 start 方法何时返回以及 main 恢复执行 内部会触发什么内容 例如向调度程序注册线程等 另外为什么要使用执行者 你打
  • 类和互斥体

    假设我有一个类代表一些名为 foo 的数据结构 class foo public foo attr01 0 void f attr01 5 private int attr01 class fooSingleThreadUserClass
  • 如何在Delphi中下载一个非常简单的HTTPS页面?

    我尝试了在这里看到的代码 但它不适用于 HTTPS 我需要将此页面作为字符串下载 并在其上添加一些换行符 以便将信息按顺序放入 TMemo 中 怎么做 我尝试使用 Indy 但由于 SSL 问题而失败 我尝试了此页面的解决方案 如何将网页下
  • C# 中的线程和 GUI 元素

    我正在尝试制作一个基本的 IRC 客户端 但我的问题是让文本显示在 RTF 框中而不出现滞后 我决定使用线程 并且我想更新线程中的 RTF 框 但我不能 因为它给了我关于 RTF 框元素不是静态的错误 有什么见解吗 如果你们想要的话我会粘贴
  • 处理 TShellListView 后代中的文件放置

    我正在尝试创建 TShellListView 的后代 它接受从 Windows 资源管理器中删除的文件 我想在组件定义中处理拖 放操作 而不必在任何使用该组件的应用程序中实现它 我找到了接受从 Windows 资源管理器中拖放的文件的示例
  • 如何在调试器中显示 TStringList 的内容?

    我想在调试应用程序时显示 TStringList 的全部内容 相反 我只是得到指示 Flist 仅显示地址 如果您使用的是 Delphi 2010 或更高版本 调试器允许使用调试可视化工具 http docwiki embarcadero
  • 如何在 Delphi DBLookupComboBox 中选择正确的项目

    我有一个数据库查找组合框连接到数据库查询 那部分工作正常 当我运行程序时数据库查找组合框填充有查询的结果 我想看看数据库查找组合框填充第一项 请选择 当 的时候程序第一次运行或者当一个新项目行动已启动 见下图 另外 如果我正在加载以前保存的
  • 如何在c#中指定时间后取消后台工作者

    如何在 C 中的指定时间后取消后台工作程序或取消无响应的后台工作程序 看看这个教程 http www albahari com threading part3 aspx http www albahari com threading par
  • TOpenDialog/NSOpenPanel 无法在沙盒 Delphi 应用程序中工作

    Firemonkey 应用程序中的 TOpenDialog 似乎存在问题 该应用程序已针对 Mac Appstore 进行沙箱处理 我使用XE3 但它也存在于XE2中 我其实在这里找到了一份QC报告 但仍然没有解决 http qc emba
  • 在调用堆栈中看到大量 clr!CLR Semaphore::Wait

    我们看到很多像下面这样的调用堆栈 我可以知道什么条件 情况会发生这种情况吗 OS Thread Id 0x48654 559 Current frame ntdll NtWaitForSingleObject 0xa Child SP Re
  • 使用 Matplotlib、PyQt 和 Threading 进行实时绘图导致 python 崩溃

    我一直在努力研究我的 Python 应用程序 但找不到任何答案 我有 PyQT GUI 应用程序 它使用 Matplotlib 小部件 GUI 启动一个新线程来处理 mpl 小部件的绘图 恐怕我现在通过从另一个线程访问 matplotlib
  • iPhone 相当于 Application.DoEvents();

    iPHone 我们使用 MonoTouch 但 Obj C 答案还可以 我的单例域对象需要一段时间才能获取所有数据 因此它在线程中内部运行部分获取数据 我需要通知 UI 域已完成 目前我正在这样做 有没有更好的办法 在 WinForms 中
  • 带等待/通知的同步块与不带等待/通知的同步块之间的区别?

    如果我只是使用synchronized 不是wait notify方法 它仍然是线程安全的吗 有什么不同 Using synchronized使方法 块一次只能由一个线程访问 所以 是的 它是线程安全的 这两个概念是结合在一起的 而不是相互
  • 如何在给定点停止线程?

    我试图停止一些线程 阅读一些有关优雅地执行此操作的正确方法的内容 但我一定做错了什么 因为它根本不起作用 起初我尝试不使用lock with IsRunning不稳定 然后尝试使用锁 这是我所拥有的 private volatile boo
  • Hazelcast 分布式锁与 iMap

    我们目前使用 Hazelcast 3 1 5 我有一个简单的分布式锁定机制 应该可以跨多个 JVM 节点提供线程安全性 代码非常简单 private static HazelcastInstance hInst getHazelcastIn
  • 用于运行可执行文件的python多线程进程

    我正在尝试将一个在 Windows 上运行可执行文件并管理文本输出文件的 python 脚本升级到使用多线程进程的版本 以便我可以利用多个核心 我有四个独立版本的可执行文件 每个线程都知道要访问它们 这部分工作正常 我遇到问题的地方是当它们

随机推荐

  • 使用 CSS GRID 为什么我会出现这种差距?

    我正在学习 CSS GRID 但我不知道为什么在下面的示例中出现空白 第二个项目可以适合第一个轨道 但我却在那里出现了间隙 这是代码 container display grid margin 40px grid gap 20px text
  • 当命名类型 T 的任何方法具有指针接收器时,复制类型 T 的实例

    I read Go 编程语言书籍最近学习golang编程语言的好资源 6 2节中有一段关于类型的复制实例T当它是指针接收器或不在方法中时 我无法理解它 有没有用一个有意义的例子来解释这一段 6 2 使用指针接收器的方法 如果命名类型 T 的
  • 使用Scrapy爬取多个域,无需纵横交错

    我已经设置了一个 CrawlSpider 聚合所有出站链接 从start urls仅通过例如一定深度DEPTH LIMIT 2 class LinkNetworkSpider CrawlSpider name network allowed
  • 尽管安装了 PIP,Python Pillow(或 PIL)仍无法工作

    我正在关注文档 https pillow readthedocs io en stable 我用 pip 成功安装了 Pillow 但是 当我尝试导入Image我可以的功能 a 仅从 PIL 导入 b 只得到没有模块的错误PILc 出现没有
  • AJAX post数据到达ASP.NET Core 2.1控制器时为空

    我使用以下 jQuery 代码将数据发布到 ASP NET Core MVC 2 1 2 页面 function OnCountryChange ajax url OnCountryChange type POST contentType
  • 如何使用正则表达式用括号将文本括起来?

    我一直试图用括号将通过正则表达式找到的一些文本括起来 例如替换全部is with is Input is This is a long sentence that IS written Desired output This is a lo
  • 我的 defaultdict(list) 不会显示在模板上,但会显示在我的视图中[重复]

    这个问题在这里已经有答案了 可能的重复 Django 模板无法循环defaultdict 我想知道为什么我的defaultdict list 当我在views py中测试它时会显示 但是当我在模板上显示数据时 我什么也没得到 甚至没有错误
  • 在处理程序中提取数据库字段值

    我想提取一个数据库字段 文本 并将其作为参数从处理程序传递给另一个函数 但是 我遇到了类型错误 完全是虚构的例子 所以可能感觉有点做作 但应该说明我遇到的问题 Person name Text Car personId PersonId n
  • Python selenium 无头模式缺少元素

    我正在使用 selenium 来抓取亚马逊搜索结果页面 当我结束它时 我将抓取转移到无头模式 因为它可以节省效率 然而在无头模式下 某些页面元素不可用比如赞助品牌 使用非无头模式时它工作得很好 但是即使设置以下选项后 使用 headless
  • 整数溢出接下来会发生什么

    我在用int 22 现在作为我的表字段 但目前它的价值已经溢出2147483647停下来 我的3000 个字段出现相同的 id 我真的很困惑 现在我改变了它bigint 20 unsigned但也许我将来也会遇到同样的情况 请建议我用什么更
  • 未调用 configurePersistentStoreCoordinator 来保存 NSPersistentDocument

    我在保存 NSPersistentDocument 时遇到了奇怪的行为 我可以创建一个自动保存的新文档 没有问题 但当我保存它时write to ofType for absoluteOriginalContentsURL 被称为但它变成了
  • fopen 返回资源 ID #4

    为什么有回声Resource id 4而不是页面本身 Because fopen 返回指向文件的资源指针 而不是文件的内容 它只是打开它以供后续读取和 或写入 具体取决于您打开文件的模式 你需要fread handle 中引用的资源中的数据
  • 从 ItemsControl 获取单击的对象并使用其属性填充 Popup

    我有一个ItemsControl它显示我的视图模型列表中的对象 我也有代码来显示Popup当用户单击 ItemsControl 中的项目时 但是我不知道如何从单击的项目中获取实际对象以读取其属性并将其显示在Popup 我有一个Click的事
  • Tibco Spotfire 中的动画数据变化

    这是我在这里发表的第一篇文章 所以如果我在此过程中在礼仪方面失败 请原谅我 我正在开发一个 POC 用于处理 Tibco Spotfire 7 0 中的可视化动画 这将允许用户通过迭代一组过滤器或基于一组预先确定的数据迭代更改数据来查看数据
  • 模加法器输出显示没有变化

    输出波形显示无变化sum dif burrow and out 即使增加延迟时间后 输出仍然没有变化 这应该像 mod 加法器一样工作 如加 10 和 2 并且 mod 3 给出输出零 CODE module Mod adder a b p
  • 缓冲流 - ASP.NET Core 3.0 中不允许同步操作

    我有一个针对 AspNetCore 2 2 的 REST API 其端点允许下载一些大的 json 文件 迁移到 AspNetCore 3 1 后 此代码停止工作 try HttpContext Response StatusCode in
  • 以“X 分钟/小时/天/周/月/年前”格式解析日期时间

    如何解析 X 分钟 小时 天 周 月 年前格式的日期 以下是一些示例来说明我所指的内容 3天前 1 分钟前 2年前 我认为使用默认的 Java 库很难做到这一点 我对吗 基于的一个小片段Calendar API Pattern p Patt
  • vue.js中的onclick多个元素

    我正在创建一个功能来隐藏和显示图像缩略图的描述 如果用户单击图像缩略图 描述将显示为动画 我已经遵循了 VueJS 中关于转换的教程 但不幸的是只有一个缩略图有效 其余的无效 我已经在我的过程中删除了脚本try and errors 那么
  • MySQL MIN/MAX 返回正确的值,但不返回相关的记录信息

    我真的很困惑 我显然不理解最小 最大概念 我正在尝试从 work type 和 work id 分组中获取最新行 如果我从 MIN 更改为 MAX 它会更改返回的时间戳 但它永远不会带来该记录中的状态信息 Example SELECT CO
  • iTask - 将参数值传递给匿名过程

    我需要创建一定数量的 iTask 来执行动态数组和记录中其他字段的操作 每个 iTask 都在该数组的特定部分中运行 该数组是记录中的一个字段 它作为 var 参数传递给 iTask 数组字段中的操作进展顺利 但其他记录字段在所有任务完成工