Delphi AsyncCalls访问冲突

时间:2014-05-27 18:50:46

标签: delphi

安迪开发的这个图书馆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.

1 个答案:

答案 0 :(得分:8)

您正在尝试使用AsyncCall的变量参数版本。该代码表示​​支持以下类型:

Supported types:
  Integer      :  Arg: Integer
  Boolean      :  Arg: Boolean
  Char         :  Arg: AnsiChar
  WideChar     :  Arg: WideChar
  Int64        :  [const] Arg: Int64
  Extended     :  [const] Arg: Extended
  Currency     :  [const] Arg: Currency
  String       :  [const] Arg: ShortString
  Pointer      :  [const] Arg: Pointer
  PChar        :  [const] Arg: PChar
  Object       :  [const] Arg: TObject
  Class        :  [const] Arg: TClass
  AnsiString   :  [const] Arg: AnsiString
  UnicodeString:  [const] Arg: UnicodeString
  PWideChar    :  [const] Arg: PWideChar
  WideString   :  [const] Arg: WideString
  Interface    :  [const] Arg: IInterface
  Variant      :  const Arg: Variant

您的函数会收到一个打开的数组参数和一个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. Made GetMax使用cdecl调用约定。
  3. max作为指向整数而不是var参数的指针。这是因为不支持var参数。
  4. GetMax使用全局变量arr,而不是将其作为参数接收。这是为了权宜之计。另一种方法是传递第一个元素的地址。
  5. 坦率地说,你的代码足够复杂,使变量参数AsyncCall感觉有点拉长。您可能最好传递一个对象或一个指向记录的指针,而不是使用变量参数重载。


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