Jump to content

Primož Gabrijelčič

Members
  • Content Count

    246
  • Joined

  • Last visited

  • Days Won

    11

Posts posted by Primož Gabrijelčič


  1. FastMM4 works perfectly and has no leaks as far as I know.  We are using FastMM4 in Delphi applications that run 24/7 for years at the time and it works just fine.

     

    That holds for the latest FastMM from https://github.com/pleriche/FastMM4. I have no idea how built-in FastMM works.

     

    One should just be careful when running FastMM4 with /dFullDebugMode. In this mode, FastMM never returns memory to the operating system and your code can run out of memory. This is a feature, not a bug.

    • Thanks 1

  2. 2 hours ago, Roberto Dall'Angelo said:

    Are there basic rules to understand the complexity? Like understand ifis O(n) or O(log n)

     

    If we are talking about time complexity (which is the usual case) and not space complexity, you can think about O() as telling you how slower your code will become if you increase the input size. Very roughly put, O(some_function_of_n) will make the code some_function_of_n slower if you increase the input by a factor of n.

     

    If your code needs M time to process m elements and you now run it on 20*m elements, O(1) will do that in time M, O(n) in time 20*M, O(n^2) in time 400*M, and O(log n) in time 4*M. 


  3. Just for the fun of it, here's a parallel version of FizzBuzz. No RNGs were abused this time.

     

    program ParallelFizzBuzz;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      Winapi.Windows,
      System.SysUtils, System.Classes;
    
    var
      GWrittenOut: TArray<boolean>;
    
    procedure FB(num: integer; output: string; extra: integer);
    begin
      TThread.CreateAnonymousThread(procedure begin
        Sleep(num* 1000 + extra);
        if not GWrittenOut[num] then begin
          Write(output, ' ');
          GWrittenOut[num] := true;
        end;
      end).Start;
    end;
    
    procedure FizzBuzz(upTo: integer);
    var
      i: integer;
    begin
      SetLength(GWrittenOut, upTo+1);
      for:= 1 to upTodo
        FB(i, i.ToString, 900);
      for:= 1 to upTo div 3 do
        FB(i*3, 'Fizz', 500);
      for:= 1 to upTo div 5 do
        FB(i*5, 'Buzz', 500);
      for:= 1 to upTo div 15 do
        FB(i*15, 'FizzBuzz', 100);
    end;
    
    var
      Msg: TMsg;
    
    begin
      FizzBuzz(20);
      while not GWrittenOut[High(GWrittenOut)] do
        while integer(PeekMessage(msg, 0, 0, 0, PM_REMOVE)) <> 0 do begin
          TranslateMessage(Msg);
          DispatchMessage(Msg);
        end;
      Writeln;
      Write('> '); Readln;
    end.

     


  4. Today I learned about pseudo random number generator driven FizzBuzz (https://stackoverflow.com/q/20957693) and I couldn't stop myself from porting it to Delphi ...

    program FizzBuzzRandom;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      System.SysUtils;
    
    procedure FizzBuzz(upTo: integer);
    var
      i: integer;
    begin
      for:= 1 to upTodo begin
        if (i mod 15) = 1 then
          RandSeed := 1973472511;
        Write(TArray<string>.Create(i.ToString, 'Fizz', 'Buzz', 'FizzBuzz')[Random(521) mod 4], ' ');
      end;
    end;
    
    begin
      FizzBuzz(100);
      Readln;
    end.

     

    • Confused 1

  5. Yes, they work 🙂 (and why wouldn't they?). 

     

    program RecursiveAnon;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      System.SysUtils;
    
    function MakeFib: TFunc<integer,int64>;
    var
      fib: TFunc<integer,int64>;
    begin
      fib :=
        function (value: integer): int64
        begin
          if value < 3 then
            Result := 1
          else
            Result := fib(value - 1) + fib(value -2);
        end;
      Result := fib;
    end;
    
    begin
      var fib := MakeFib;
      for var:= 1 to 10 do
        Write(fib(i), ' ');
    
      Readln;
    end.

     

    • Like 1
    • Thanks 1

  6. Indeed, I got the "obvious" part from Hoare 🙂

     

    The parallel part is all mine though. And I stand behind it.

     

    If one writes a unit test which tests the specification in full, it can in theory prove that a single-threaded unit complies with the specification.

     

    Throwing parallel processing in the mix, however, prevents us from even that result. At most one can say is that the unit probably works as expected inside one test environment on one computer.

    • Like 1

  7. 1 hour ago, Rudy Velthuis said:

    Obviously testing thread-related code is hard too. :classic_wink:

    Indeed.

     

    In single-threaded code, good unit tests will show that the code obviously has no errors.

    In multi-threaded code, good unit tests will show that the code has no obvious errors.

     

    IOW, unit tests can only prove that your multi-threaded code doesn't work, not that it does.

    • Like 2

  8. BTW, OmniThreadLibrary's TOmniBoundedQueue was implemented in 2008. Then we needed about a year to find few weird boundary conditions where the code would crash and fix them. 

     

    After that the queue was working perfectly until 2018, when I found a race condition which caused the queue to say "sorry, can't add an item, the queue is full", when the queue has actually just become empty. Nobody noticed the problem in the meantime, we all thought the code is perfect, and the unit/stress test did not test for this specific scenario ...

     

    Writing lock-free structures is harder than you think. (Applies to me, too.)

    • Like 1
    • Thanks 1

  9. The writer also doesn't work.

     

    function TMWSRList.AddItem(pItem : Integer):Integer;
    var
      aOverFlow : Integer;
    begin
      Result := InterlockedIncrement(FWriteIndex);
    
      if Result >= MAX_SIZE then
      begin
        aOverFlow := Result - MAX_SIZE;
    	
        { Reset FWriteIndex when it reaches MAX_SIZE }
        InterlockedCompareExchange(FWriteIndex, -1, MAX_SIZE + aOverFlow);
        Result := InterlockedIncrement(FWriteIndex);
      end;
    
      FItems[Result] := pItem;
      InterlockedIncrement(FAvailableCount);
    
      if Assigned(FOnNewItemAdd) then  
        FOnNewItemAdd(self);
    end;
    1. FWriteIndex is at the end of array.
    2. Two threads call AddItem.
    3. Both threads increment FWriteIndex.
    4. Both threads enter `if`.
    5. Second thread executes InterlockedCompareExchange and InterlockedIncrement. That will skip slot 0 which will never be used, if I'm not mistaken.

    Plus - what use is InterlockedCompareExchange if you never test if the exchange was successful?

     

    Plus - the code doesn't work if the queue overflows (reader stops but writers keep writing). But that is by design, I guess?

     


  10. Definitely doesn't work correctly. For starters, two parallel readers would clash horribly.

     

    If you want to implement lock-free structures, start by writing thorough stress-tests. They should run different scenarios - one reader, few readers, many readers ... very many readers (more than the number of cores in the system) - in a loop which runs for a long time (minutes, at least, preferably more).  

     

    If you want to use something that is well-tested, take TOmniBoundedQueue from the OmniThreadLibrary.

    • Like 1

  11. Original post: https://www.thedelphigeek.com/2019/02/design-patterns-with-delphi-book.html

     

    Hurrah, hurray, my third book is here! It’s called Hands-On Design Patterns with Delphi and (just like my first book) I wrote it for Packt Publishing. (The second book was self-published and I expect the fourth one to be, too.)

     

    As the name says, “Design Patterns with Delphi” deals with design patterns. It is a bit different from most of design pattern books and websites you will find on the Internet. Case in point A: There are no UML diagrams. I don‘t speak UML. Tried to learn it few times but for some reason the whole concept doesn‘t agree with me. If you like diagrams, don’t fear though. Any book on design patterns - and most websites covering that topic - will gladly show how any design pattern can be diagrammed. That, however, is not important and should not govern your decision to buy the book.

    B11287%20(2).png

    More important is case in point B: This book speaks Delphi. All the examples are written in Delphi and language features are used to the full. I also covered few less known Delphi idioms in separate sections. You’ll still be able to follow the discussion even though you may program in a different Pascal dialect.

     

    There’s also case in point 😄 Examples make sense. I deeply dislike classical design pattern examples of the “And then we want to write this program for different toolkits and it should also be able to draw circles, not only squares” kind. Euch! I tried to find a good example for each design pattern. Admittedly, I ended with few examples that draw triangles and squares on screen (mostly because some patterns were designed specifically for solving such problems), but most of them are of a more practical nature.

     

    This book covers all three classical design pattern categories - Creational patterns, Structural patterns, and Behavioral patterns. It also discusses patterns from the newer Concurrency patterns category. At the end I threw in some borderline-pattern(ish) topics and ended with a discussion of few patterns that cannot be strictly classified as “design” patterns.

    In this book you’ll find:

    • Chapter 1

      An introduction to patterns. Exploration of design principles, design patterns, and idioms. A mention of anti-patterns. A short description of most important design principles. Delphi idioms: creating and destroying objects.
    • Chapter 2

      Creation patterns part 1. Singleton. Dependency injection. Lazy initialization. Object pool.
    • Chapter 3

      Creation patterns part 2. Factory method, Abstract factory, Prototype, Builder. Delphi idioms: Assign and AssignTo.
    • Chapter 4

      Structural patterns part 1. Composite. Flyweight. Marker interface. Bridge. Delphi idioms: comparers and hashers.
    • Chapter 5

      Structure patterns part 2. Adapter. Proxy. Decorator. Facade. Delphi idioms: replacing components in runtime. Also: helpers.
    • Chapter 6

      Behavioral patterns part 1. Null object. Template method. Command. State.
    • Chapter 7

      Behavioral patterns part 2. Iterator. Visitor. Observer. Memento. Delphi idioms: for .. in.
    • Chapter 8

      Concurrency patterns part 1. Locking. Lock striping. Double-checked locking. Optimistic locking. Readers-writers lock. Delphi idioms: tasks and threads. Also: bitwise operators.
    • Chapter 9

      Concurrency patterns part 2. Thread pool. Messaging. Future. Pipeline.
    • Chapter 10

      Writing Delphi programs. Event-driven programming. Actions. LiveBindings. Form inheritance. Frames. Data modules.
    • Chapter 11

      Wrapping it up. Exceptions. Debugging. Functional programming.

     

    I hope you will like this book and learn a lot from it. I know I did during the nine months I spent writing it. And if you find any bug in the code, let me know so I can correct it in the second release!

    • Like 11
    • Thanks 14
×