Revised by
Stefan Glienke
ed64243
| program Project1;
{$APPTYPE CONSOLE}
uses
Generics.Defaults,
SysUtils, Threading;
type
ILock = interface
procedure Enter;
procedure Leave;
end;
PMonitorRec = ^TMonitorRec;
TMonitorRec = record
Vtable: Pointer;
RefCount: Integer;
Instance: TObject;
end;
function NopQueryInterface(inst: Pointer; const IID: TGUID; out Obj): HResult; stdcall;
begin
Result := E_NOINTERFACE;
end;
function MemAddRef(inst: PMonitorRec): Integer; stdcall;
begin
Result := AtomicIncrement(inst.RefCount);
end;
function MemRelease(inst: PMonitorRec): Integer; stdcall;
begin
Result := AtomicDecrement(inst.RefCount);
if Result = 0 then
begin
System.MonitorExit(inst.Instance);
FreeMem(inst);
end;
end;
procedure MonitorEnter(inst: PMonitorRec);
begin
System.MonitorEnter(inst.Instance);
end;
procedure MonitorLeave(inst: PMonitorRec);
begin
System.MonitorExit(inst.Instance);
end;
const
Monitor_Vtable: array[0..4] of Pointer =
(
@NopQueryInterface,
@MemAddref,
@MemRelease,
@MonitorEnter,
@MonitorLeave
);
function Lock(const instance: TObject): ILock;
var
inst: PMonitorRec;
begin
System.MonitorEnter(instance);
GetMem(inst, SizeOf(TMonitorRec));
inst.Vtable := @Monitor_Vtable;
inst.RefCount := 0;
inst.Instance := instance;
Result := ILock(inst);
end;
var
o: TObject;
i: Integer;
begin
o := TObject.Create;
i := 0;
TParallel.&For(1, 1000,
procedure(x: Integer)
begin
Lock(o);
Inc(i);
Sleep(1);
Dec(i);
Assert(i = 0);
end);
o.Free;
end.
|