Recent

Author Topic: Simple multithreading code example in Free Pascal  (Read 24968 times)

semichaud1

  • New Member
  • *
  • Posts: 38
Simple multithreading code example in Free Pascal
« on: April 12, 2018, 10:14:47 pm »
Hi,

I'm looking for a simple multithreading code example in Free Pascal. How to create threads and use them in the code.

I am currently programming a 2d video game using Free Pascal (v2.6.2.i386-win32) and SDL2 (v2.0.1) and I want to use two threads to process each half of the array I use to display graphics in a grid like fashion on the screen.

Thanks!
« Last Edit: April 13, 2018, 05:18:53 pm by semichaud1 »

ezlage

  • Guest

semichaud1

  • New Member
  • *
  • Posts: 38
Re: Simple multithreading code example in Free Pascal
« Reply #2 on: April 12, 2018, 10:30:18 pm »
Thanks! I actually went through this tutorial several times but it's doing much more than what I need multithreading for. It seems like the most complicated example of multithreading. I'm looking for somethig simple that I can use for my game to split up the processing of the grid map. If you don't mind could you give me an example of how I would use multithreading in my code to process each half of a grid array[1..100,1..200]?
« Last Edit: April 12, 2018, 10:40:42 pm by semichaud1 »

ezlage

  • Guest
Re: Simple multithreading code example in Free Pascal
« Reply #3 on: April 12, 2018, 10:48:52 pm »
Try to create a Thread that knows how to do all the work, and through a parameter in the Create procedure you limit the scope of action. Then, you create a Threads vector, initialize each position limited to one part of the grid, and then execute all of them.

I have attached the closest code on your needs I've developed (a dedup ratio calculator). Is a very specific and ancient code.

Sorry by my poor English.

Code: Pascal  [Select][+][-]
  1.   TAUThread = class(TThread)
  2.     protected
  3.       _ID: Int64;
  4.       _FileToScan: string;
  5.       _FileName: string;
  6.       _CurrentHash: string;
  7.       _CurrentStart: qword;
  8.       _CurrentEnd: qword;
  9.       _CurrentSize: qword;
  10.       _BlockSize: qword;
  11.       _FileSize: qword;
  12.       _FileParts: qword;
  13.       _ScannedSize: qword;
  14.       _ScannedParts: qword;
  15.       procedure Execute; override;
  16.     private
  17.       procedure SendCurrentStatus;
  18.       procedure SendStartStatus;
  19.       procedure SendEndStatus;
  20.     public
  21.       constructor Create(const CreateSuspended, AutoFree: boolean; const FileToScan: string; BlockSize: QWord; const ID: Int64=-1);
  22.     published
  23.   end;
  24.  
  25. {...}
  26.  
  27. var
  28.   Form1: TForm1;
  29.   Robots: array of TAUThread;
  30.  
  31. {...}
  32.  
  33.  

semichaud1

  • New Member
  • *
  • Posts: 38
Re: Simple multithreading code example in Free Pascal
« Reply #4 on: April 12, 2018, 11:22:40 pm »
Thank you very much! I tried implementing the code but it doesn't work for me. I tried following this tutorial: http://wiki.freepascal.org/Multithreaded_Application_Tutorial#Units_needed_for_a_multi-threaded_application, but I do not understand a lot of the examples of code used in there. Most seem to go beyond what is being explained. I think it's too advanced for me. I have been programming in Pascal for 21 years though. But the code in the tutorial is just confusing. I cannot match it with the explanation. All I want to do is have a thread run half the array for the grid map and another thread run the other half. That's all. But the example in the tutorial has code all over the place with no logical connection between them that I can understand.
« Last Edit: April 12, 2018, 11:59:37 pm by semichaud1 »

lainz

  • Hero Member
  • *****
  • Posts: 4593
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: Simple multithreading code example in Free Pascal
« Reply #5 on: April 13, 2018, 03:31:55 am »
There is a good component to run tasks in separate threads.
https://github.com/wadman/wthread/

reinerr

  • New Member
  • *
  • Posts: 37
Re: Simple multithreading code example in Free Pascal
« Reply #6 on: April 13, 2018, 04:18:43 am »
Have attached a sample app which processes a random "grid" (it actually does random sleeps). In the app you can hit the button as many times as you want and the threads will go off and do their "processing" and return whenever they are finished.

Note, there is a thread-safe Progress property that could be used to check the progress of a thread from elsewhere. In the example I remember the last thread that was started and display its progress (while it exists).

-Reiner

Leledumbo

  • Hero Member
  • *****
  • Posts: 8772
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Simple multithreading code example in Free Pascal
« Reply #7 on: April 13, 2018, 06:19:52 am »
As simple as it can be but not simpler:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2.  
  3. uses
  4.   {$ifdef unix}
  5.   cthreads,
  6.   {$endif}
  7.   Classes;
  8.  
  9. type
  10.   TMyThread = class(TThread)
  11.     procedure Execute; override;
  12.   end;
  13.  
  14. procedure TMyThread.Execute;
  15. begin
  16.   WriteLn('I am thread with ID ',ThreadID);
  17. end;
  18.  
  19. var
  20.   t1,t2,t3: TThread;
  21. begin
  22.   // create all threads in suspended state
  23.   t1 := TMyThread.Create(true); t1.FreeOnTerminate := true;
  24.   t2 := TMyThread.Create(true); t2.FreeOnTerminate := true;
  25.   t3 := TMyThread.Create(true); t3.FreeOnTerminate := true;
  26.  
  27.   t1.Start; t2.Start; t3.Start; // start them all
  28.   t1.WaitFor; t2.WaitFor; t3.WaitFor; // wait for them all to finish before exiting main thread
  29. end.
  30.  

semichaud1

  • New Member
  • *
  • Posts: 38
Re: Simple multithreading code example in Free Pascal
« Reply #8 on: April 13, 2018, 05:13:15 pm »
Perfect. Thank you all. I'm going to try out those codes.

semichaud1

  • New Member
  • *
  • Posts: 38
Re: Simple multithreading code example in Free Pascal
« Reply #9 on: April 17, 2018, 11:58:54 pm »
So I managed to get multithreading working but it turns out that I cannot use commands relating to graphics in anything other than the main thread which defeats what I wanted to use multithreading for (have one thread render half the grid and another the other half). So I moved the code for calculations, such as character positions and movement, to an additional thread and left everything else including graphics in the main thread. I made sure that all variables I'm using in the additional thread are not used at all in the main thread. My characters on screen are shaking when moving and I think it's due to the calculations and graphics not being synced. So basically the graphics still depend on player position calculation, which is normal. I can't think of a way to make this independent. In order to draw the graphics I need to know the position of each character. When I move characters around the additional thread processes their movements and new positions, the main thread renders the characters on screen and those two things happened asynchronously due to multithreading. I tried inserting a conditional statement to only render characters once the additional thread doing calculations is done but that did not solve the issue.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Simple multithreading code example in Free Pascal
« Reply #10 on: April 18, 2018, 12:28:16 am »
Perhaps i've missed something but i read: video game, free pascal and sdl.

SDL has it's own threading implementation, and one that (also) states:
Quote
NOTE: You should not expect to be able to create a window, render, or receive events on any thread other than the main one. For platform-specific exceptions or complicated options ask on the forums/mailing list.

When i read:
Quote
...have one thread render half the grid and another the other half...
Then i believe you are a) misunderstanding something about threads (it simply doesn't work that simple as you seem to think) and b) making your life overly complicated for nothing.

You can use another thread as you did and update your (internal) grid so the main thread can use that. If you do not sync that correctly then yes your graphics can appear shaking. Remember that you can 'update' your graphics faster then you are able to calculate your grid (as well as the opposite). They do not have to be in sync and you are allowed to update your graphics even when you are in the middle of calculating/updating your grid. Hint: also read up on double/triple buffering.

It is very difficult to give you a copy-paste solution because it depends on your implementation. Also note that using opengl with threads has a different set of rules as gl can be done multi-threading when done properly and worker threads can be used.
« Last Edit: April 18, 2018, 12:40:35 am by molly »

semichaud1

  • New Member
  • *
  • Posts: 38
Re: Simple multithreading code example in Free Pascal
« Reply #11 on: April 18, 2018, 02:17:13 am »
I'm using Free Pascal and SDL 2. I could not find an SDL 2 multithread library for Free Pascal. As long as the graphics to be rendered depends on calculations or values of some variables, such as player coordinates on the grid, that are being run by the additional thread, the graphics will not be in sync and show this shaking effect probably because it is displaying graphics faster than the additional thread can calculate new variable values. So I inserted a condition to not render any graphics until the additional thread returns a value of 1 for a variable I used to indicate that all the lines of codes in the additional thread have run. This did not fix the issue. I will try again and see if I can do it differently.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Simple multithreading code example in Free Pascal
« Reply #12 on: April 18, 2018, 02:32:34 am »
I'm using Free Pascal and SDL 2. I could not find an SDL 2 multithread library for Free Pascal.
it should be part of the standard sdl header. There is no separate sdl multithread library. Your sdl libs are either compiled with threading enabled or not. which headers are you using ?

Quote
As long as the graphics to be rendered depends on calculations or values of some variables, such as player coordinates on the grid, that are being run by the additional thread, the graphics will not be in sync and show this shaking effect probably because it is displaying graphics faster than the additional thread can calculate new variable values. So I inserted a condition to not render any graphics until the additional thread returns a value of 1 for a variable I used to indicate that all the lines of codes in the additional thread have run. This did not fix the issue. I will try again and see if I can do it differently.
Try to update your graphics at a constant rate (vsync or a timer comes to mind). In case nothing changed (or you do not want half your gfx updated) then use a second (static) buffer that you keep displaying at that constant rate and refresh the buffers (bufferswap) once your calculations are done. Then repeat the same process.

fwiw: a knowledgeable person once wrote:
Quote
There is a saying in computer science:
Premature optimization is the root of all evil

A major problem with newbie programmers is that they want to be like the professionals without paying their dues. They hear about a technology that the latest and greatest developers out there are using and they think if the use it too it will make them magically better.

One of these tools is multithreading. Since multicore processors launched at a consumer level in the early 00s, developers have been using this new tech to squeeze out as much performance as they can from their applications.

Here's the important part: a poorly made multithreaded program can perform worse than single thread program. Much worse. The fact is that multithreading inherently adds more overhead because threads then have to be managed. If you do not know the costs of using different multithreading tools, you can end up with code that is much slower than its single threaded equivalent.

The general rule is if you don't know:
  • What cache coherency is.
  • What cache alignment is.
  • How operating systems handle threads and processes.
  • How to use a profiler.

You should not be trying to use multithreaded optimization. Play with fire and you will get burned. However doing something not for the sake of performance like asynchronous file loading isn't a bad idea for intermediate game developers.

semichaud1

  • New Member
  • *
  • Posts: 38
Re: Simple multithreading code example in Free Pascal
« Reply #13 on: April 18, 2018, 02:36:23 am »
So from what I can figure the shaking graphics (only characters are shaking, the background tiles are not) comes from the fact that the main thread is rendering the characters while the additional thread is still processing the characters coordinates when they move. So I have no choice but to include the procedure in the main thread instead. I will find some other use for the additional thread, for example quicksaves without interrupting gameplay. I was thinking I could also use an additional thread for the calculations relating to combat in the game. Then have the main thread render the combat graphics separately but I will have to only process variables that have no impact on the graphics at all. Like how much hp a target loses and what status effects are applied but that's so low in computational demands that I'm starting to wonder why have multithreading at all except for quicksaves. Sound effects maybe.

I'm using:

uses sdl2, sdl2_image, sdl2_ttf, sdl2_mixer, sdl_gfx, crt,
{$ifdef unix}
cthreads,
{$endif}
Classes;

I have my own implementation of vsync in the main thread in the main loop:

var
        fpscapstate:boolean; { =true: cap fps }
   selfps:byte;
   fpstick:uint32;

selfps:=60;
if fpscapstate=true then fpstick:=sdl_getticks;
{ code: calculations, keyboard, mouse and controller input, etc }
{ render graphics }
if fpscapstate=true then
begin
   fpstick:=sdl_getticks-fpstick;
   if fpstick<1000/selfps then sdl_delay(round((1000/selfps)-fpstick));
end;

I'm not familiar with programming for buffers except maybe when I was using sdl 1. But in sdl 2 now I am rendering all graphics using hardware. I only use surfaces to load bmp files (outside of the main loop) and then load those surfaces into textures only because sdl 2 does not offer any other solution I know of to apply a color key to a texture loaded from the hard drive. I understand the idea behind using two buffers but it feels like a waste to me when I could be making the game only render (sdl_renderpresent) when everything is ready. Which I tried to do already. I know about that saying from the Lazyfoo tutorials. I'm not trying to be like professionals. I did mention earlier in the post that multithreading could be too advanced for me. But I have been programming for 21 years and with Pascal since 2004. I've never studied computer programming. I learned all on my own. I actually work in Accounts :). I tried following free pascal multithreading tutorials but they seem very poor to me. Despite reading them over and over, I can't understand all of it because there are a lot of assumptions being made in the tutorial regarding prerequisite knowledge. Anyway, I have multithreading working. It's just that I need to figure out how to restructure my code in order to avoid that shaking effect.


« Last Edit: April 18, 2018, 02:51:46 am by semichaud1 »

cdbc

  • Hero Member
  • *****
  • Posts: 1588
    • http://www.cdbc.dk
Re: Simple multithreading code example in Free Pascal
« Reply #14 on: April 18, 2018, 02:38:24 am »
Hi
Have a look at the Omni-Lib:
http://www.omnithreadlibrary.com/
It is very good!
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

 

TinyPortal © 2005-2018