【问题标题】:Delphi AsyncCalls Access ViolationDelphi AsyncCalls 访问冲突
【发布时间】:2014-05-27 18:50:46
【问题描述】:

Andy 开发的这个库AsynCalls 给我留下了深刻的印象。

我写了一段代码只是为了测试这个库,但它总是获取内存 A/V,我是不是漏掉了什么?

以下代码旨在使用两个异步线程并行这个简单的任务(从数组中获取最大值)。

program Test;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Math,
  Windows,
  Forms,
  AsyncCalls in 'AsyncCalls.pas';

var
  arr: array of integer;
  i: integer;

procedure GetMax(const arr: array of integer; left, right: integer; var max: integer);
var
  i: integer;
begin
  max := arr[left];
  for i := left + 1 to right do
  begin
    if (arr[i] > max) then
    begin
      max := arr[i];
    end;
  end;
end;

const
  N = 100000;

var
  a, b: IAsyncCall;
  maxv, max1, max2: integer;

begin
  SetLength(arr, N);
  maxv := -1;
  for i := 0 to High(arr) do
  begin
    arr[i] := RandomRange(0, MaxInt);
    if (arr[i] > maxv) then
    begin
      maxv := arr[i];
    end;
  end;

  a := AsyncCall(@GetMax, [arr, 0, Length(arr) div 2, max1]);
  b := AsyncCall(@GetMax, [arr, (Length(arr) div 2) + 1, High(arr), max2]);
  while (AsyncMultiSync([a, b], True, 10) = WAIT_TIMEOUT) do
  begin
    Application.ProcessMessages;
  end;
  Writeln(max1, ', ', max2, ', ', Max(max1, max2));
  Writeln(maxv);
  Readln;
end.

【问题讨论】:

  • 你为什么在控制台应用程序中调用ProcessMessages
  • 没关系,我去掉了,还是会造成A/V
  • 为卓越的 SSCCE +1!

标签: delphi


【解决方案1】:

您正在尝试使用AsyncCall 的可变参数版本。代码说支持以下类型:

支持的类型: 整数:Arg:整数 布尔值:Arg:布尔值 字符:Arg:AnsiChar WideChar : Arg: WideChar Int64 : [const] Arg: I​​nt64 扩展:[const] Arg:扩展 货币:[const] Arg:货币 字符串:[const] 参数:短字符串 指针:[const] 参数:指针 PChar : [const] Arg: PChar 对象:[常量] 参数:TObject 类:[const] 参数:TClass AnsiString : [const] Arg: AnsiString UnicodeString:[const] 参数:UnicodeString PWideChar : [const] Arg: PWideChar WideString : [const] 参数:WideString 接口:[const] 参数:IInterface 变体:const Arg:变体

您的函数接收一个开放数组参数和一个var 参数,在上面的列表中都找不到。此外,该函数必须使用cdecl 调用约定。

这是您的代码的一个有效版本:

program Test;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Math,
  AsyncCalls in 'AsyncCalls.pas';

var
  arr: array of integer;

procedure GetMax(left, right: integer; max: PInteger); cdecl;
var
  i: integer;
begin
  max^ := arr[left];
  for i := left + 1 to right do
  begin
    if (arr[i] > max^) then
    begin
      max^ := arr[i];
    end;
  end;
end;

const
  N = 100000;

var
  a, b: IAsyncCall;
  i, maxv, max1, max2: integer;

begin
  SetLength(arr, N);
  maxv := -1;
  for i := 0 to High(arr) do
  begin
    arr[i] := RandomRange(0, MaxInt);
    if (arr[i] > maxv) then
    begin
      maxv := arr[i];
    end;
  end;
  a := AsyncCall(@GetMax, [0, Length(arr) div 2, @max1]);
  b := AsyncCall(@GetMax, [(Length(arr) div 2) + 1, High(arr), @max2]);
  AsyncMultiSync([a, b], True, INFINITE);
  Writeln(max1, ', ', max2, ', ', Max(max1, max2));
  Writeln(maxv);
  Readln;
end.

请注意,我做了以下更改:

  1. 删除了 Forms 的使用和对 ProcessMessages 的调用。
  2. 使GetMax 使用cdecl 调用约定。
  3. max 作为指向整数的指针而不是var 参数传递。那是因为不支持var 参数。
  4. GetMax 使用全局变量arr 而不是将其作为参数接收。那是为了权宜之计。另一种方法可能是传递第一个元素的地址。

坦率地说,您的代码非常复杂,以至于变量参数AsyncCall 感觉有些牵强。你可能会更好地传递一个对象,或者一个指向记录的指针,而不是使用可变参数重载。


我还应该指出,不再开发 AsyncCalls。在我看来,采用 OTL 会比 AsyncCalls 更好地为您服务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多