我在Android服务项目中使用Delphi 10.1.2。我已经按照可用的示例来管理TTask.Run线程。我使用Array of ITask
和TList<ITask>
尝试了代码,但错误是相同的。
{$define TASK_ARRAY}
{$ifdef TASK_ARRAY}
TaskArray: Array of ITask;
{$else}
TaskList: TList<ITask> // has the same problem
{$endif}
线程的创建是异步的,实际上是由GPS驱动的......
procedure TMainService.SendNewPosition(Username: String; NewLocation: TLocationCoord2D;
PosTimeStamp: TDateTime; UseColor: TAlphaColor);
var
ATask: ITask;
begin
...
ATask := TTask.Create(procedure
begin
// a small procedure that runs very quickly
// but which is called very frequently
end
);
if ATask <> nil then // trying to eliminate the problem
begin
{$ifdef TASK_ARRAY}
SetLength(TaskArray, Length(TaskArray) + 1);
TaskArray[High(TaskArray)] := ATask;
{$else}
TaskList.Add(ATask);
{$endif}
ATask.Start;
end;
稍后,在AndroidServiceTrimMemory
事件处理程序中,我执行此操作:
var
i: Integer;
ATask: ITask;
begin
try
{$ifdef TASK_ARRAY}
i := High(TaskArray);
// try to delete any nil ITask before WaitForAll finds it
while i > -1 do
begin
ATask := ITask(TaskArray[i]);
if ATask = nil then // never happens
begin
Delete(TaskArray,i,1);
i := High(TaskArray);
end
else
Dec(i);
end;
TTask.WaitForAll(TaskArray, Wait);
SetLength(TaskArray, 0);
{$else}
TTask.WaitForAll(TaskList.ToArray, Wait);
Tasklist.Clear;
{$endif}
except
on e: exception do
Log(e.Message); // 'At least one task in array nil'
end;
现在我有机会追踪到TTask.WaitforAll
和TTask.DoWaitForAll
,以查看引发异常的位置:
for I := High(Tasks) downto Low(Tasks) do
begin
Task.Value := TTask(Tasks[I]);
if Task.Value = nil then
raise EArgumentNilException.CreateRes(@sWaitNilTask);
当引发错误时,I
有时为1,有时为0. High(Tasks)
可能是4或5.每次运行都会发生错误。
所有评论都表示赞赏。
**在Remi的评论之后编辑**
我将system.threading复制到我的项目中并对DoWaitForAll进行了一些小改动(带超时的重载)
var
ATask: ITask;
...
for I := High(Tasks) downto Low(Tasks) do
begin
ATask := ITask(Tasks[I]); // casts correctly
if ATask <> nil then
begin
Task.Value := TTask(Tasks[I]); // doesn't cast correctly
if Task.Value = nil then
raise EArgumentNilException.CreateRes(@sWaitNilTask);
这有点过头了。但也许其他人明白这里发生了什么?
答案 0 :(得分:-1)
如果有人关注这个问题,我只想描述我采用的解决方案。即。这是我的应用问题的答案,而不是我的问题的答案。我使用了以下代替Array of ITask
或TaskList: TList<ITask>
的代码:
FThreads: TObjectList<TThread>;
...
constructor TMainService.Create(Owner: TComponent);
...
FThreads := TObjectList<TThread>.Create(True);
AThread := TThread.CreateAnonymousThread(procedure
begin
// this dummy thread does nothing
end
);
AThread.FreeOnTerminate := False;
FThreads.Add(AThread); // so ARC won't throw FThreads away (it happened!)
...
procedure TMainService.SendNewPosition(Username: String; NewLocation: TLocationCoord2D;
PosTimeStamp: TDateTime; UseColor: TAlphaColor);
var
AThread: TThread;
...
AThread := TThread.CreateAnonymousThread(
procedure
begin
// a small procedure that runs very quickly
// but which is called very frequently
end
);
AThread.FreeOnTerminate := False;
FThreads.Add(AThread);
AThread.Start;
稍后,在AndroidServiceTrimMemory事件处理程序中,我这样做:
i := 1; // preserve the dummy thread reference
while i < FThreads.Count do
begin
AThread := FThreads.Items[i];
AThread.WaitFor;
Inc(i);
end;
// delete all but the dummy thread [0]
while FThreads.Count > 1 do
begin
i := FThreads.Count - 1;
FThreads.Delete(i);
FThreads.TrimExcess;
end;