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.
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:
Forms
and the call to ProcessMessages
.GetMax
use the cdecl
calling convention.max
as a pointer to integer rather than a var
parameter. That is because var
parameters are not supported.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With