Threading OSX and DYLIBs lazarus / 33-macOS - Mac OS X ---------------------------------------------------------------------- kevin.black · 2019-06-13 03:28 MBP with parallels Mojave VM lazarus 2.0.0RC3 I have read the tutorial docs WRT threading and it appears quite straight forward. I say that noting that so far, everything I have tried on OSX either hasn't worked or required some not so obvious surgery to get it to work. Threading under windows seems to work fine, on OSX not so much. Again, I have pursued the forum and wiki and not getting much out of it. Here are my code snippets, most of which is straight out of the tutorial: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$mode objfpc}{$H+}{$ModeSwitch pChartoString}{$define UseCThreads} interface uses  {$IFDEF UNIX}  {$IFDEF UseCThreads}  cthreads,  {$ENDIF}  {$ENDIF}  Interfaces,......const  {$IFDEF MSWINDOWS}  EmpyreanAPIDLL = 'DbXServerAPI.dll';  libEmpyreanCrypto = 'libEmpyreanCrypto.dll';  {$ENDIF MSWINDOWS}  {$IFDEF DARWIN}  EmpyreanAPIDLL = 'libdbxserverapi.dylib';  {$linklib libdbxserverapi.dylib}  libEmpyreanCrypto = 'libEmpyreanCrypto.dylib';  {$linklib libEmpyreanCrypto.dylib}  {$ENDIF DARWIN}......type  TgetStatusThread = class(TThread)  private    fStatusText: string;    eMail: string;    procedure ShowStatus;  protected    procedure Execute; override;  public   Constructor Create(CreateSuspended : boolean);end;......function checkUserStatus(loginName: pChar; out successBoolean: pChar;  out responseMessage: pChar; out errorCode: pChar; out errorMessage: pChar)  : integer;  {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external EmpyreanAPIDLL;...... constructor TgetStatusThread.Create(CreateSuspended : boolean);begin  inherited Create(CreateSuspended);  FreeOnTerminate := True;end;......procedure TfEMPServerTest.bCheckUserStatusClick(Sender: TObject);var  getStatusThread: TgetStatusThread; begin  WriteLog('DEBUG', 'in TfEMPServerTest.bCheckUserStatusClick');  getStatusThread := TgetStatusThread.Create(True);  WriteLog('DEBUG', 'before start');  getStatusThread.Email := checkUserStatusEmailEdit.Text;  getStatusThread.Start;     // START THE THREAD - YES THIS WORKS  WriteLog('DEBUG', 'after start'); end; procedure TgetStatusThread.ShowStatus;// this method is executed by the mainthread and can therefore access all GUI elements.begin  fEMPServerTest.Memo1.Lines.Add('Status Returned: ' + fStatusText);  showmessage('TgetStatusThread.ShowStatus Status Returned: ' + fStatusText);  WriteLog('DEBUG', 'Status Returned: ' + fStatusText);end; procedure TgetStatusThread.Execute;var  successBoolean: pChar;  responseMessage: pChar;  errorCode: pChar;  errorMessage: pChar;  ReturnResult: integer;  newStatus : string; begin  Writelog('DEBUG', 'In TgetStatusThread.Execute Thread');   // I DEFINATELY GET HERE AND THE LOG IS WRITTEN TO  fStatusText := 'TgetStatusThread Starting...';  Writelog('DEBUG', fStatusText);  Synchronize(@Showstatus);  fStatusText := 'TgetStatusThread Running...';  Writelog('DEBUG', fStatusText);  Synchronize(@Showstatus);  responseMessage := 'Nil Response';  ReturnResult := checkUserStatus(pChar(Email), successBoolean, responseMessage, errorCode, errorMessage);  // THIS IS A CALL TO A FUNCTION IN A DYLIB AND IT HANGS HERE  WriteLog('DEBUG', 'TgetStatusThread.Execute after checkUserStatus');                                     // NEVER EXECUTED  fStatusText := 'Return Result: ' + inttostr(ReturnResult) + #13#10 + 'Response: ' + string(responseMessage);  Synchronize(@Showstatus);  fStatusText := 'TgetStatusThread Terminating...';  Synchronize(@Showstatus);  WriteLog('DEBUG', fStatusText);   while (not Terminated) and (responseMessage = 'Nil Response')do  begin    NewStatus := 'TgetStatusThread Update';    Writelog('DEBUG', NewStatus);    if NewStatus <> fStatusText then    begin      fStatusText := newStatus;      Writelog('DEBUG', 'TgetStatusThread Loop synchronize');      Synchronize(@Showstatus);    end;  end; end;  Problem #1: So the first issue is that Synchronize never executes the ShowStatus method (hence the gazillion Writelog statements so I can see what's happening). Is this some issue with OSX or is it something else more insidious? Problem #2: When I get to the external function (which works fine if I just call it from the main thread), the code simply hangs. To complicate matters, I am trying to have this DYLIB and it's functions used by a C++ developer on macOS. If he calls from the main thread then OK, if he calls the DYLIB function from a secondary thread it crashes his application. But first things first, does the DYLIB function need anything special to be called from a secondary thread, and what is a likely reason it is causing the call to hang? If you need any other/further info let me know. Would I have any better success with one of the other lazarus thread libraries like say WThread? Thanks, Kevin ---------------------------------------------------------------------- skalogryz · 2019-06-13 13:21 1) for this particular issue I can definitely recommend to try using Lazarus trunk. There were a number of changes done on how Synchronize() work. 2) The crashes from the secondary thread depend on how the function is written. Typically a pure function like Min() or Max() would work fine. BUT if a function is using some global objects, then it might crash pretty fast. A special consideration for macOS. It might require a special NSAutorelease object to be created on the thread. However, those could be created by the later OSX versions ---------------------------------------------------------------------- kevin.black · 2019-06-13 22:51 @skalogryz, 1. Thank you. I have installed FPC fixes 3.2.0 and lazarus 2.1.0. I'll junk that and try and install fixes 3.2.0 and lazarus trunk. 2. The function within the DYLIB calls a couple of internal functions (mainly writing to the log) and performs a REST call using some of the TMS Dropbox component classes, the returned JSON is then decoded in another function. In Delphi/Win32 I have used these classes within a DLL called by a thread and there has been no issues that I am aware of. The only other function is one to allocate memory etc to the pChar values returned.  There are, AFAICT, no globals etc etc, but I cannot confirm that in the TMS code. Regardless, first thing to try is the install of Fixes/trunk. Thanks for the advice. Cheers, Kevin ---------------------------------------------------------------------- kevin.black · 2019-06-14 02:35 So on the basis that it never rains it pours: I have installed FPC 3.2/Lazarus TrunkWhen I try to build the test application it can no longer find any of the DYLIBSAll of the library paths are the same (it drags this in with the lpr file for each project)Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  {$IFDEF MSWINDOWS}  EmpyreanAPIDLL = 'DbXServerAPI.dll';  libEmpyreanCrypto = 'libEmpyreanCrypto.dll';  {$ENDIF MSWINDOWS}  {$IFDEF DARWIN}   EmpyreanAPIDLL = 'libdbxserverapi.dylib';  {$linklib libdbxserverapi.dylib}  libEmpyreanCrypto = 'libEmpyreanCrypto.dylib';  {$linklib libEmpyreanCrypto.dylib}and these lines are causing the linker error that the libraries are not found (to be safe, I have put the DYLIBs in the app folder, in the app itself, in a library folder and in /usr/local/lib, yet all I get is this library not found error trying to build): QuoteMessages, Warnings: 17, Hints: 78 ... ... Error: ld: library not found for -ldbxserverapi An error occurred while linking Error: Error while linking So I cannot even tryout the 'fixes' in lazarus trunk until I can sort out the libraries not found (which TBF is seeming a little daunting, I cannot imagine where the linker is looking and why it isn't looking at the folders where the DYLIBs are). Does anyone know why the DYLIBs are not being found in this frehs install? Thanks, Kevin