Jump to content

pyscripter

Members
  • Content Count

    785
  • Joined

  • Last visited

  • Days Won

    42

Posts posted by pyscripter


    • Andreas Hausladen. Obones and  and a few others have been quite active in maintaining JCL/JVCL. 
    • Although, there are no recent releases the recommended installation procedure involves using the GitHub master.  See https://github.com/project-jedi/jcl for details.
    • JCL/JVCL support all Delphi versions including the most recent ones.
    • There have been tens of commits fixing warnings and minors bugs over the last few months (https://github.com/project-jedi/jcl/commits/master)
    • There are masses of gems in both JCL and JVCL that are still worth using in production code.

     

    • Like 6

  1. LoadResStringW is not a Windows function.  It s a function defined with the gettext unit.   The THook is used to direct calls from System.LoadResString to gettext's LoadResStringW. It also redirects a bunch of other functions related to resource strings.

     

    Say for example this is your program:

     

    resourcestring

      Test = 'Hello"

    ...

    ShowMessage(Test);

     

    Your program will show the translation of Test, if it exists in the translated messages for the current language and if not it will show 'Hello'.

     

     


  2. 8 minutes ago, Sue King said:

    Do you mean so that if there isn't something for gettext and there is a resource translation, there is only one call ? 

      {$ifdef UNICODE}
      HookLoadResString:=THook.Create (@system.LoadResString, @LoadResStringW);
      {$else}
      HookLoadResString:=THook.Create (@system.LoadResString, @LoadResStringA);
      {$endif}

     

    The system functions are replaced with gettext versions that return translated strings.  So wherever you use resource strings translated values will appear.

    • Thanks 1

  3. The code:

     var C: AnsiChar := #$0A;
     if C in [#$A, #$D] then

    Generates the following assembly code in 32 bits.

    Project2.dpr.26: var C: AnsiChar := #$0A;
    004F9C10 C645FF0A         mov byte ptr [ebp-$01],$0a
    Project2.dpr.41: if C in [#$A, #$D] then
    004F9C14 8A45FF           mov al,[ebp-$01]
    004F9C17 2C0A             sub al,$0a
    004F9C19 7404             jz $004f9c1f
    004F9C1B 2C03             sub al,$03
    004F9C1D 751C             jnz $004f9c3b

    On the other hand 

    var C: Char := #$0A0A;  
      if C in [#$A, #$D] then

    generates the following:

    Project2.dpr.26: var C: Char := #$0A0A;
    004F9C10 66C745FE0A0A     mov word ptr [ebp-$02],$0a0a
    Project2.dpr.41: if C in [#$A, #$D] then
    004F9C16 668B45FE         mov ax,[ebp-$02]
    004F9C1A 6683E80A         sub ax,$0a
    004F9C1E 7406             jz $004f9c26
    004F9C20 6683E803         sub ax,$03
    004F9C24 751C             jnz $004f9c42

    Notice that it handles the wide char correctly.  However the compiler issues the following warning:

    [dcc32 Warning] Project2.dpr(41): W1050 WideChar reduced to byte char in set expressions.  Consider using 'CharInSet' function in 'SysUtils' unit.

    Question 1:  Why the warning is issued, given that the generated code does not reduce the wide char to a byte?

    Question 2:  Doesn't this mean that RSP-13141 has been resolved except for the warning?   In the discussion of that issue @Arnaud Bouchez points out that the warning is misleading.

     

    In 64 bit the generated code looks much more complex:

    Project2.dpr.26: var C: Char := #$0A0A;
    00000000005716E8 66C7452E0A0A     mov word ptr [rbp+$2e],$0a0a
    Project2.dpr.41: if C in [#$A, #$D] then
    00000000005716EE 480FB7452E       movzx rax,word ptr [rbp+$2e]
    00000000005716F3 6683E808         sub ax,$08
    00000000005716F7 6683F807         cmp ax,$07
    00000000005716FB 7718             jnbe TestCharInSet + $35
    00000000005716FD B201             mov dl,$01
    00000000005716FF 8BC8             mov ecx,eax
    0000000000571701 80E17F           and cl,$7f
    0000000000571704 D3E2             shl edx,cl
    0000000000571706 480FB60556000000 movzx rax,byte ptr [rel $00000056]
    000000000057170E 84C2             test dl,al
    0000000000571710 0F95C0           setnz al
    0000000000571713 EB02             jmp TestCharInSet + $37
    0000000000571715 33C0             xor eax,eax
    0000000000571717 84C0             test al,al
    0000000000571719 7422             jz TestCharInSet + $5D

    Question 3: Why is the code is so more complex in 64 bits?  Please forgive my ignorance.

    • Like 2

  4. @Stefan GlienkeIt does depend on what you are testing.  If one claims that it takes > 1s for the first task to execute, it is sufficient to show it is not true.   Also the work load on many real-life multi-threaded applications is not dissimilar.   Say you fire 100 HTTP requests and you wait for the results to come, or you do asynchronous IO with memory mapped files (using overlapped events).

     

    I like this use of language:

    • No doubt … followed by a debatable statement
    • It is clear that … followed by an unclear statement
    • No offence …. followed by an offensive statement
    • etc.
    • Thanks 1
    • Haha 1

  5. The optimal thread pool configuration for IO intensive task is of course different that that for computational intensive tasks.  The first case calls for many more threads than the second, since the tasks are in waiting state most of the time.  System.Threading allows to have separate thread pools for different sets of tasks.


  6. 

    Quote

     

    "Annoying and uncontrollable behavior"

     

    @Primož GabrijelčičAt least in Rio it seems to work OK:

    program Project2;
    {$APPTYPE CONSOLE}
    uses
      WinApi.Windows,
      System.Diagnostics,
      System.Threading;
    
    procedure TestParallel;
    Var
      TaskArray:  array [1..100] of ITask;
    begin
      for var I := Low(TaskArray) to High(TaskArray) do
        TaskArray[I] := TTask.Create(procedure
        begin
          Sleep(100);
        end).Start;
      TTask.WaitForAll(TaskArray);
    end;
    
    begin
      var SW := TStopWatch.StartNew;
      //TThreadPool.Default.SetMinWorkerThreads(50);
      TestParallel;
      WriteLn(SW.ElapsedMilliseconds);
      WriteLn;
      Var TPS := TThreadPoolStats.Default;
      WriteLn('WorkerThreadCount: ', TPS.WorkerThreadCount);
      WriteLn('MinLimitWorkerThreadCount: ', TPS.MinLimitWorkerThreadCount);
      WriteLn('MaxLimitWorkerThreadCount: ', TPS.MaxLimitWorkerThreadCount);
      ReadLn;
    end.

    Output on an 8 processor machine:

    1370
    
    WorkerThreadCount: 9
    MinLimitWorkerThreadCount: 8
    MaxLimitWorkerThreadCount: 200

    Output with TThreadPool.Default.SetMinWorkerThreads(50);

     

    233
    
    WorkerThreadCount: 50
    MinLimitWorkerThreadCount: 50
    MaxLimitWorkerThreadCount: 200

    With TParallel.&For it works differently and the number of threads created relate to the number of processors.

     

     

    • Like 2

  7. Please allow me to disagree.  I have made non-trivial use of System.Threading in PyScripter (used by thousands of users)  without any problems. The main issue I know of with the library is RSP-11267.   You can see a fix in that report, but even without the fix you can work around the issue by using a different mechanism for signalling task to stop  As for Parallel.For I have not used it extensively, but you can see some code of mine in this StackOverflow question that I think is now used in a commercial product.  An issue with thread creation by Parallel.For (RSP-21177) has been fixed in Rio.

     

    Advantages of System.Threading:

    •  By far the easiest way to use tasks (as opposed to threads) in your delphi application
    • Nice interface using anonymous methods 
    • Avoids third-party dependencies
    •  It provides usage statistics that can be used for diagnostic purposes
    •  Nowadays, it provides good performance out of the box, but you can still fine-tune the way it works if you are prepared to dig-in
    •  It uses state-of-the-art synchronization techniques
    •  @Primož Gabrijelčič can correct me on this, but by reading his book "Delphi High Performance", I think, that depending on the type of use, is competitive if not faster than his own OmniThreadLibrary

    The Parallel library, like many other new features of Delphi (e.g. Generics) got a bad reputation, due to the many bugs in the early days.  Unfortunately. trust is easy to lose and very hard to rebuild.  But the library does deserves some love from Embarcadero (fixing remaining issues) and Delphi users.   

    • Like 2
    • Thanks 2

  8. CreateWindowHandle/CreateWnd are VCL Wincontrol routines that can be overwritten to take action that needs to happen when the WindowHandle of a control gets (re)created.  There are corresponding routines DestroyWindowHandle/DestroyWnd,  but these routines are only called when the control is recreated and not when it is destroyed.  It appears that this is known, see for example here and here.  

     

    I came across this issue because I wanted to do the following when a contol's handle was created:

        RegisterDragDrop (Handle, DropTarget);

    and this has to be matched by:

        RevokeDragDrop(Handle);

    at handle destruction.  Initially I placed the first statement in an overwritten CreateWindowHandle and the second in DestroyWindowHandle.   This resulted in memory leaks and I began to investigate.  Here are the results of the investigation that I wanted to share with you in case you face the same issue.

     

    1. DestroyWnd is only called when recreating the control (not at control destruction).  It also calls DestroyWindowHandle.  This is documented in the help file.

    2, DestroyWindowHandle is called by DestroyWnd and separately by TWinControl.Destroy if WindowHandle <>0.

     

    So it looks like my solution should work, however, when the control is a child of a TCustomForm and the form gets destroyed (almost always the case), TCustomForm.Destroy calls DestroyWindowHandle before destroying child objects and Windows, before destroying a control's handle, it first destroys the window handles of all child objects. So the DestroyWindowHandle of the child controls will not be called!  WindowHandle = 0 inside TWinControl.Destroy.  The choices you have for taking action before handle destruction are:

     

    3. WM_DESTROY handler.   It is called by windows before destroying the window handle of child controls.

    4 WM_NCDESTROY handler. It is called by windows after destroying the window handle of child controls and before destroying the control's window handle.

     

    I ended up putting RevokeDragDrop inside the WM_DESTROY handler, since this is called in all cases the window handle gets destroyed.

     

    Although not a bug, this looks like bad VCL design to me and can be the source of many bugs.

    • Thanks 3
×