- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要创建一定数量的 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
问题是:运行所有 iTask 后,只有动态数组字段 recarray.vet
包含正确的值。字段 recarray.total
和 recarray.average
仍然包含 iTask 运行之前的初始值。
如何正确更新这些字段中的值,以便任务完成运行后它们将包含正确的值?
最佳答案
虽然您的代码似乎只有一个问题 - 如何用任务填充记录中的整数字段 - 当您解决这个问题时,您将遇到另一个问题 - 从多个线程读取和写入相同的内存位置。
<强>1。如何填充记录中的整数字段?
记录是值类型,动态数组是引用类型。这就是为什么您的代码可以更新数组中的值但无法更新记录中的值的原因。
让我们看看这里发生了什么。
function CreateTask(first, last: integer; var pmyrec: myrec): ITask;
var
mylocalrec: myrec;
begin
mylocalrec := pmyrec;
由于 mylocalrec
和 pmyrec
是记录(值类型),因此它们的内容将占用两个不同的内存位置。上述作业会将 pmyrec
的内容复制到 mylocalrec
中。
这相当于以下内容:
mylocalrec.vet := pmyrec.vet;
mylocalrec.total := pmyrec.total;
mylocalrec.average := pmyrec.average;
由于 total
和 average
也是值类型,因此它们的内容将被复制,从此时起,对 mylocalrec
中的任何一个整数字段进行任何更改code> 不会对原始 pmyrec
产生任何影响。这就是您的代码失败的原因。
为什么将动态数组字段 vet
从 pmyrec
分配给 mylocalrec
有效?
因为动态数组是引用类型 - 从一个变量到另一个变量的赋值仅复制引用(指针)的值,而不是实际内容。两个 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。如何解决线程问题?
解决原始问题后,您将遇到线程问题。从多个线程读取和写入同一内存位置是不安全的。您得到的结果可能不正确。虽然您可以运行代码数千次并且所有值都可能正确,但迟早您会遇到它们不正确的情况。
在您的情况下,填充动态数组是安全的,因为每个线程都在数组的不同部分上操作,并且在任务运行时不会重新分配数组(其大小不会更改)。这部分代码是线程安全的。
计算总计
和平均值
不是线程安全的。
您必须将此类代码与主线程同步 - 在这种情况下,所有读取和写入都将从主线程完成,您将获得正确的结果。或者您必须在所有任务完成后运行此类代码。哪个更适合特定情况。
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.
关于multithreading - iTask - 将参数值传递给匿名过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51292602/
SELECT ID, AppID, Description, Min([Transaction Date]) AS TransactionDate FROM AppProsHist WHERE [De
目前我正在创建规则,该规则应该检查方法是否包含 @Test 和 @TestInfo 注释。如果确实如此,@TestInfo 不应有空参数 testCaseId。 有几种不同的可能方法来填充 testC
是否可以设置参数值,使其在 where 子句中始终结果为 true? 作为示例,考虑一个查询: SELECT name FROM student WHERE class=@parameter; 现在我
我是 JPA 的新手,这是我的查询之一,我有几个参数作为查询的一部分,任何参数都可以为空值 @Query(value = "SELECT ord.purchaseOrderNumber,ord.sal
LOD 参数对 texturelod 取什么值? ?我发现的规范根本没有提到它。它是百分比还是带有百分比的索引值。如果是后者,有没有办法获得纹理具有的 mipmap 数量,以便我能够使用百分比? 最佳
我希望此代码替换现有的 URL 参数“aspid”,但它的作用是在现有的 id 上添加另一个 id。有人可以帮忙吗? $(document).ready(function() { function
在 Spring-boot 项目中,我尝试将 Date 对象作为请求参数传递,并收到此错误: Parameter value [1] did not match expected type [java
在我们的 Jenkinsfile 中,我们有很多参数(参数化构建),在这种情况下,我想检查每个参数是否已切换并对其进行操作。这些参数具有相似的名称,但以不同的小数结尾,因此我想迭代它们以实现此目的。
我的模板之一中有类似于以下内容的内容: 但是 Freemarker 不高兴并给了我: Exception in thread "main" freemarker.core.ParseExceptio
我正在从表单向重定向 servlet 发送一个 post 请求。然后,Servlet 将表单写入其响应 (getWriter) 对象。该表单包含许多隐藏字段。我使用 javascript 提交此表单(
我正在创建一个 JavaScript 组件,我正在根据 jQuery 结果创建该组件的实例,但是,我传递到构造函数中的 DOM 元素虽然在我单步执行调用代码中的循环时已填充,但在传递给构造函数时是未定
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我对 javascript 有疑问。 假设我有这样的 javascript 函数: function show_popup(id) { alert(id); } 编
我目前正在尝试抓取嵌入式 m3u8 url 路径以进行自学。 到目前为止,我设法确定请求会生成带有 m3u8 信息的 json 响应。 例如,https://headlines.yahoo.co.jp
谷歌地图 API 需要这样的参数: NSString *urlString=@"http://maps.google.com/maps?saddr=43.2923,5.45427&daddr=43.4
“parameterValue”是在 Javascript 中的事件上传递的默认参数吗?谁能解释一下这个值从何而来。 Load Ajax content 我发现它在以下文章中使用 - http://w
我有一个 .SWF 电子邮件提交表单。背景颜色通过以下方式设置: `` 并嵌入: `` 是否可以将鼠标悬停在对象或包含的 div 上来更改这些值?即#ffffff 非常感谢! 最佳答案 将 wmode
假设我想用指数函数拟合两个数组x_data_one和y_data_one。为此,我可以使用以下代码(其中 x_data_one 和 y_data_one 被赋予虚拟定义): import numpy
有什么方法可以填充 parameters在基于外部属性文件内容的 Liquibase 变更日志文件中? 例如,我希望能够说: 并将 table.name 的值和
我必须按原样发送参数值 'AbCd/EfgH'。但是 Angular 将 '/' 转义为 %2F。我无法控制 URL。 解决这个问题的最佳方法是什么? 我不想强制 Angular 停止对所有其他 UR
我是一名优秀的程序员,十分优秀!