Al Boldi wrote:
Michael Van Canneyt wrote:
On Sat, 15 Dec 2007, Al Boldi wrote:
melchiorre caruso wrote:
I found an article that explains why my code does not work on Windows:
Actually, I had a closer look at synchronize, and it turns out to be
dependent on the GUI, which probably means that you need to include
'Interfaces' in your library uses clause.  Can you try this on windows?
No.
Synchronize does not depend on the GUI, it does depend on the main
thread calling CheckSynchronize from time to time.

The problem is that synchronize depends on calling WakeMainThread, but that only gets set when you include the Interfaces unit.

melchiorre caruso wrote:
libthread.dpr(4,3) Fatal: Can't find unit Interfaces used by libthread

I add manually  $(LazarusDir)\lcl\interfaces\$(TargetOS) to the paths but
an other error occours:

Fatal: Can't find unit InterfaceBase used by Interfaces

"The dog bites the tail"

I use WinXp Sp2
Lazarus svn
Fcp 2.2.0

Try adding the LCL to your project.
I added the LCL to my project;
Now the compiler founds interfaces units and builds all source;
But Synchronize does not work.
But, you could instead just try setting WakeMainThread in your lib yourself, and let the handler post a message to the mainthread. That's what the Interfaces unit does. Can you try this

I do not know how to do it,

Btw, I solved the problem using threadx.pas;

Thanks
---
Melchiorre




unit threadx;

interface

uses
  Windows,
  Classes;

type
  TThreadSynchronizer = class
  private
    FMethod: TThreadMethod;
    FSynchronizeException: TObject;
    FSyncBaseThreadID: LongWord;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Synchronize(Method: TThreadMethod);
    property SyncBaseThreadID: LongWord read FSyncBaseThreadID;
  end;

  TThreadEx = class(TThread)
  private
    FSynchronizer: TThreadSynchronizer;
    procedure HandleTerminate;
  protected
    procedure DoTerminate; override;
  public
    constructor Create(CreateSuspended: Boolean);
    destructor Destroy; override;
    procedure Wait;
    property Synchronizer: TThreadSynchronizer read FSynchronizer;
  end;
  
implementation

const
  CM_EXECPROC = $8FFD;
  CM_DESTROYWINDOW = $8FFC;

type
  TSyncInfo = class
    FSyncBaseThreadID: LongWord;
    FThreadWindow: HWND;
    FThreadCount: Integer;
  end;

  TSynchronizerManager = class
  private
    FThreadLock: TRTLCriticalSection;
    FList: TList;
    procedure FreeSyncInfo(AInfo: TSyncInfo);
    procedure DoDestroyWindow(AInfo: TSyncInfo);
    function InfoBySync(ASyncBaseThreadID: LongWord): TSyncInfo;
    function FindSyncInfo(ASyncBaseThreadID: LongWord): TSyncInfo;
  public
    class function Instance: TSynchronizerManager;
    constructor Create();
    destructor Destroy; override;
    procedure AddThread(ASynchronizer: TThreadSynchronizer);
    procedure RemoveThread(ASynchronizer: TThreadSynchronizer);
    procedure Synchronize(ASynchronizer: TThreadSynchronizer);
  end;

var
  SynchronizerManager: TSynchronizerManager;

function ThreadWndProc(Window: HWND; Message, wParam, lParam: Longint): 
Longint; stdcall;
begin
  case Message of
    CM_EXECPROC:
      with TThreadSynchronizer(lParam) do
      begin
        Result := 0;
        try
          FSynchronizeException := nil;
          FMethod();
        except
          FSynchronizeException := AcquireExceptionObject();
        end;
      end;
    CM_DESTROYWINDOW:
      begin
        TSynchronizerManager.Instance().DoDestroyWindow(TSyncInfo(lParam));
        Result := 0;
      end;
  else
    Result := DefWindowProc(Window, Message, wParam, lParam);
  end;
end;

var
  ThreadWindowClass: TWndClass = (
    style: 0;
    lpfnWndProc: @ThreadWndProc;
    cbClsExtra: 0;
    cbWndExtra: 0;
    hInstance: 0;
    hIcon: 0;
    hCursor: 0;
    hbrBackground: 0;
    lpszMenuName: nil;
    lpszClassName: 'TThreadSynchronizerWindow');

{ TSynchronizerManager }

constructor TSynchronizerManager.Create;
begin
  inherited Create();
  InitializeCriticalSection(FThreadLock);
  FList := TList.Create();
end;

destructor TSynchronizerManager.Destroy;
var
  i: Integer;
begin
  for i := FList.Count - 1 downto 0 do
  begin
    FreeSyncInfo(TSyncInfo(FList[i]));
  end;
  FList.Free();
  DeleteCriticalSection(FThreadLock);
  inherited Destroy();
end;

class function TSynchronizerManager.Instance: TSynchronizerManager;
begin
  if (SynchronizerManager = nil) then
  begin
    SynchronizerManager := TSynchronizerManager.Create();
  end;
  Result := SynchronizerManager;
end;
    
procedure TSynchronizerManager.AddThread(ASynchronizer: TThreadSynchronizer);

  function AllocateWindow: HWND;
  var
    TempClass: TWndClass;
    ClassRegistered: Boolean;
  begin
    ThreadWindowClass.hInstance := HInstance;
    ClassRegistered := GetClassInfo(HInstance, ThreadWindowClass.lpszClassName,
      TempClass);
    if not ClassRegistered or (@TempClass.lpfnWndProc <> @ThreadWndProc) then
    begin
      if ClassRegistered then
        Windows.UnregisterClass(ThreadWindowClass.lpszClassName, HInstance);
      Windows.RegisterClass(ThreadWindowClass);
    end;

    Result := CreateWindow(ThreadWindowClass.lpszClassName, '', 0,
      0, 0, 0, 0, 0, 0, HInstance, nil);
  end;

var
  info: TSyncInfo;
begin
  EnterCriticalSection(FThreadLock);
  try
    info := FindSyncInfo(ASynchronizer.SyncBaseThreadID);
    if (info = nil) then
    begin
      info := TSyncInfo.Create();
      info.FSyncBaseThreadID := ASynchronizer.SyncBaseThreadID;
      FList.Add(info);
    end;
    if (info.FThreadCount = 0) then
    begin
      info.FThreadWindow := AllocateWindow();
    end;
    Inc(info.FThreadCount);
  finally
    LeaveCriticalSection(FThreadLock);
  end;
end;

procedure TSynchronizerManager.RemoveThread(ASynchronizer: TThreadSynchronizer);
var
  info: TSyncInfo;
begin
  EnterCriticalSection(FThreadLock);
  try
    info := InfoBySync(ASynchronizer.SyncBaseThreadID);
    PostMessage(info.FThreadWindow, CM_DESTROYWINDOW, 0, Longint(info));
  finally
    LeaveCriticalSection(FThreadLock);
  end;
end;

procedure TSynchronizerManager.DoDestroyWindow(AInfo: TSyncInfo);
begin
  EnterCriticalSection(FThreadLock);
  try
    Dec(AInfo.FThreadCount);
    if AInfo.FThreadCount = 0 then
    begin
      FreeSyncInfo(AInfo);
    end;
  finally
    LeaveCriticalSection(FThreadLock);
  end;
end;

procedure TSynchronizerManager.FreeSyncInfo(AInfo: TSyncInfo);
begin
  if AInfo.FThreadWindow <> 0 then
  begin
    DestroyWindow(AInfo.FThreadWindow);
    AInfo.Free();
    FList.Remove(AInfo);
  end;
end;

procedure TSynchronizerManager.Synchronize(ASynchronizer: TThreadSynchronizer);
begin
  SendMessage(InfoBySync(ASynchronizer.SyncBaseThreadID).FThreadWindow, 
CM_EXECPROC, 0, Longint(ASynchronizer));
end;

function TSynchronizerManager.FindSyncInfo(
  ASyncBaseThreadID: LongWord): TSyncInfo;
var
  i: Integer;
begin
  for i := 0 to FList.Count - 1 do
  begin                       
    Result := TSyncInfo(FList[i]);
    if (Result.FSyncBaseThreadID = ASyncBaseThreadID) then Exit;
  end;
  Result := nil;
end;

function TSynchronizerManager.InfoBySync(
  ASyncBaseThreadID: LongWord): TSyncInfo;
begin
  Result := FindSyncInfo(ASyncBaseThreadID);
  Assert(Result <> nil, 'Cannot find SyncInfo for the specified thread 
synchronizer');
end;

{ TThreadSynchronizer }

constructor TThreadSynchronizer.Create;
begin
  inherited Create();
  FSyncBaseThreadID := GetCurrentThreadId();
  TSynchronizerManager.Instance().AddThread(Self);
end;

destructor TThreadSynchronizer.Destroy;
begin
  TSynchronizerManager.Instance().RemoveThread(Self);
  inherited Destroy();
end;

procedure TThreadSynchronizer.Synchronize(Method: TThreadMethod);
begin
  FSynchronizeException := nil;
  FMethod := Method;
  TSynchronizerManager.Instance().Synchronize(Self);
  if Assigned(FSynchronizeException) then raise FSynchronizeException;
end;

{ TThreadEx }

constructor TThreadEx.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  FSynchronizer := TThreadSynchronizer.Create();
end;

destructor TThreadEx.Destroy;
begin
  FSynchronizer.Free();
  inherited Destroy();
end;

procedure TThreadEx.DoTerminate;
begin
  if Assigned(OnTerminate) then Synchronizer.Synchronize(HandleTerminate);
end;

procedure TThreadEx.HandleTerminate;
begin
  if Assigned(OnTerminate) then OnTerminate(Self);
end;

procedure TThreadEx.Wait;
var
  Msg: TMsg;
  H: THandle;
begin
  DuplicateHandle(GetCurrentProcess(), Handle, GetCurrentProcess(), @H, 0, 
False, DUPLICATE_SAME_ACCESS);
  try
    if GetCurrentThreadID = Synchronizer.SyncBaseThreadID then
    begin
      while MsgWaitForMultipleObjects(1, H, False, INFINITE, QS_SENDMESSAGE) = 
WAIT_OBJECT_0 + 1 do
      begin
        while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
        begin
          DispatchMessage(Msg);
        end;
      end;
    end else
    begin
      WaitForSingleObject(H, INFINITE);
    end;
  finally
    CloseHandle(H);
  end;
end;

initialization
  SynchronizerManager := nil;

finalization
  SynchronizerManager.Free();
  SynchronizerManager := nil;

end.

Reply via email to