Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi AsyncCalls Access Violation

Tags:

delphi

I am impressed by this Library AsynCalls developed by Andy.

I write a piece of code just to test the library, but it always gets memory A/V, did I miss something here?

The following code is intended to parallel this simple task (get maximum from an array) using two asynchronous threads.

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.
like image 519
justyy Avatar asked May 27 '14 18:05

justyy


1 Answers

You are attempting to use the variable parameter version of AsyncCall. The code says that the following types are supported:

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

Your function receives an open array parameter and a var parameter, neither to be found in the list above. What's more, the function must use the cdecl calling convention.

Here is a version of your code that does work:

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.

Note that I made the following changes:

  1. Removed the use of Forms and the call to ProcessMessages.
  2. Made GetMax use the cdecl calling convention.
  3. Pass max as a pointer to integer rather than a var parameter. That is because var parameters are not supported.
  4. Let GetMax use the global variable arr rather than receive it as a parameter. That was for expediency. An alternative might be to pass the address of the first element.

Frankly, your code is complex enough to make the variable parameter AsyncCall feel a little stretched. You might be better passing an object, or a pointer to a record rather than using the variable parameter overload.


I should also point out that AsyncCalls is no longer developed. You would, in my view, be better served by adopting OTL than AsyncCalls.

like image 64
David Heffernan Avatar answered Sep 28 '22 09:09

David Heffernan