Recent

Author Topic: Terminating a subroutine without multithreading?  (Read 7901 times)

CM630

  • Hero Member
  • *****
  • Posts: 1091
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Terminating a subroutine without multithreading?
« on: August 03, 2018, 05:01:42 pm »

I need to show images in a popup window when mouse points a hyperlink.
This includes loading (usually from HTTP), resizing (always), cropping(always) and rotating (if necessary) of the images.
The problem is that when the mouse is moved to another hyperlink I need to terminate loading, etc. processing of the image and start processing the image pointed in the new hyperlink.

I tried to use multithreading, but sometimes application crashes without giving me an idea when and why. It exits and using TRY... EXCEPT... FINALLY does not help at all.
So I wonder if there is a way to terminate a routine without using multithreading?
Лазар 3,2 32 bit (sometimes 64 bit); FPC3,2,2; rev: Lazarus_3_0 on Win10 64bit.

tudi_x

  • Hero Member
  • *****
  • Posts: 532
Re: Terminating a subroutine without multithreading?
« Reply #1 on: August 03, 2018, 05:17:43 pm »
hi,
without multithreading the main thread will be busy resizing the image, thus blocking the UI (until process messages) thus degrading the UX.
no fluid UI.

do you have some code that you suspect is creating the errors?
Lazarus 2.0.2 64b on Debian LXDE 10

CM630

  • Hero Member
  • *****
  • Posts: 1091
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Terminating a subroutine without multithreading?
« Reply #2 on: August 06, 2018, 10:18:49 am »
Too bad to hear it, but not unexpected.
I suppose that subroutines called by a threads do not get terminated whet thread is terminated.
Maybe I shall use no subroutines. I will try to create a standalone sample... in a month or two.
Лазар 3,2 32 bit (sometimes 64 bit); FPC3,2,2; rev: Lazarus_3_0 on Win10 64bit.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Terminating a subroutine without multithreading?
« Reply #3 on: August 06, 2018, 10:58:08 am »
Too bad to hear it, but not unexpected.
I suppose that subroutines called by a threads do not get terminated whet thread is terminated.
that makes no sense if a thread is terminated the subroutine can not keep executing.
Maybe I shall use no subroutines. I will try to create a standalone sample... in a month or two.
ok now I'm confused what do you mean by subroutines?
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11452
  • FPC developer.
Re: Terminating a subroutine without multithreading?
« Reply #4 on: August 06, 2018, 11:18:30 am »
(btw terminating threads is not recommended. You can do it on shutdown if everything fails, but it is not really safe to do so and continue normal operation after)

CM630

  • Hero Member
  • *****
  • Posts: 1091
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Terminating a subroutine without multithreading?
« Reply #5 on: August 06, 2018, 12:08:02 pm »

ok now I'm confused what do you mean by subroutines?

Functions and procedures.

(btw terminating threads is not recommended. You can do it on shutdown if everything fails, but it is not really safe to do so and continue normal operation after)

Ok, so I will have to do some reading if I cannot go without multithreading.


This says something about Destroy, but example for Create does not compileError: Wrong number of parameters specified for call to "RTLEventCreate")‟

Code: Pascal  [Select][+][-]
  1. type
  2.   TMyThread = class(TThread)
  3.   private
  4.     fRTLEvent: PRTLEvent;
  5.   public
  6.     procedure Create(SomeData: TSomeObject); override;
  7.     destructor Destroy; override;
  8.   end;
  9.  
  10. procedure TMyThread.Create(SomeData: TSomeObject; CreateSuspended: boolean);
  11. begin
  12.   // example: set up events, critical sections and other ressources like files or database connections
  13.   RTLEventCreate(fRTLEvent);
  14.   inherited Create(CreateSuspended);
  15. end;
  16.  
  17. destructor TMyThread.Destroy;
  18. begin
  19.   RTLeventDestroy(fRTLEvent);
  20.   inherited Destroy;end;
« Last Edit: August 06, 2018, 12:30:45 pm by CM630 »
Лазар 3,2 32 bit (sometimes 64 bit); FPC3,2,2; rev: Lazarus_3_0 on Win10 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 14371
  • Sensorship about opinions does not belong here.
Re: Terminating a subroutine without multithreading?
« Reply #6 on: August 06, 2018, 02:27:29 pm »
In the case of threads,simply wait for a thread to finish. It is called waitfor.
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

CM630

  • Hero Member
  • *****
  • Posts: 1091
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Terminating a subroutine without multithreading?
« Reply #7 on: August 06, 2018, 02:39:24 pm »
I cannot wait. Loading and processing an image might take hundreds of milliseconds.
When hyperlinks are ordered vertically, mouse might get through many of them until getting to the desired one.
But indeed, I will check if I have a delay before positioning mouse cursor and the beginning of the loading process. A delay of 50 ms seems quite reasonable.
Лазар 3,2 32 bit (sometimes 64 bit); FPC3,2,2; rev: Lazarus_3_0 on Win10 64bit.

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 844
Re: Terminating a subroutine without multithreading?
« Reply #8 on: August 06, 2018, 08:56:35 pm »
You should use old trick, well known since Win 3.0 era - software multitasking. Divide both loading and processing into small steps, so you will be able to abandon this process and exit thread at any moment. Please remember, that hardware multitasking doesn't mean OS will do all the job for you. You still need to do it yourself.
Is it healthy for project not to have regular stable releases?
Just for fun: Code::Blocks, GCC 13 and DOS - is it possible?

sash

  • Sr. Member
  • ****
  • Posts: 366
Re: Terminating a subroutine without multithreading?
« Reply #9 on: August 06, 2018, 09:46:31 pm »
I cannot wait. Loading and processing an image might take hundreds of milliseconds.

- If processing works only for hundreds of milliseconds, create Thread with FreeOnTerminate or Anonymous, let it process image and store result when ready, optionally check Terminated during Execute on each processing step, if you're not caching (probably you should) results.

- Each worker thread should signal popup of image readiness with RTLEvents or Anonymous thread callbacks.

- When you need to show a new popup - start a new thread, ignoring old one that is working, optionally call Old.Terminate.

- Also using a guard delay is a good idea to limit useless popup/thread launches.


Well, if you're not familiar with threads, locks and events, this is a little tricky, but doable.
Lazarus 2.0.10 FPC 3.2.0 x86_64-linux-gtk2 @ Ubuntu 20.04 XFCE

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Terminating a subroutine without multithreading?
« Reply #10 on: August 06, 2018, 10:15:43 pm »
Code: Pascal  [Select][+][-]
  1.   procedure TWorkerThread.Execute;
  2.   var
  3.     Duties:array[0..3] of TProcedure;// = (@loadImage, @resizeImage, @cropImage, @rotateImage);
  4.     Duty: TProcedure;
  5.   begin
  6.     Duties[0] := @loadImage;
  7.     Duties[1] := @resizeImage;
  8.     Duties[2] := @cropImage;
  9.     Duties[3] := @rotateImage;
  10.     ...
  11.     for Duty in Duties do
  12.       if Terminated then
  13.         exit
  14.       else
  15.         Duty;
  16.  
  17.     //Notify GUI thread to show the image
  18.   end;

Notice that you can call TFPHTTPClient.terminate to stop loading, soon.

CM630

  • Hero Member
  • *****
  • Posts: 1091
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Terminating a subroutine without multithreading?
« Reply #11 on: August 07, 2018, 06:51:17 am »
I think I will try @Mr.Madguy's proposal without any threads to see how it will look like and how long exactly processing an image might take, and then I will search a harder solution if necessary.
I think that this will I have problems mostly with SMB (at least DobleCommander hangs for minutes, when trying to access a switched off/disconnected SMB source). But that is not an issue for this topic.
« Last Edit: August 07, 2018, 01:11:39 pm by CM630 »
Лазар 3,2 32 bit (sometimes 64 bit); FPC3,2,2; rev: Lazarus_3_0 on Win10 64bit.

sash

  • Sr. Member
  • ****
  • Posts: 366
Re: Terminating a subroutine without multithreading?
« Reply #12 on: August 07, 2018, 09:33:44 am »
2px formatting ... :)
I think I will try @Mr.Madguy's proposal without any threads to see how it will look like and how long exactly processing an image might take, and then I will search a harder solution if necessary.
I think that this will I have problems mostly with SMB (at least DobleCommander hangs for minutes, when trying to access a switched off/disconnected SMB source). But that is not an issue for this topic.

The problem is that @Mr.Madguy's proposal is actually harder than threads (not to say impossible to implement a task as defined).
Because all synchronous tasks in libraries, not written by you cannot be canceled easily/at all.
Lazarus 2.0.10 FPC 3.2.0 x86_64-linux-gtk2 @ Ubuntu 20.04 XFCE

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 844
Re: Terminating a subroutine without multithreading?
« Reply #13 on: August 07, 2018, 02:09:45 pm »
I think I will try @Mr.Madguy's proposal without any threads to see how it will look like and how long exactly processing an image might take, and then I will search a harder solution if necessary.
I think that this will I have problems mostly with SMB (at least DobleCommander hangs for minutes, when trying to access a switched off/disconnected SMB source). But that is not an issue for this topic.

No, you still can use threads. Threads are actually required for some tasks, such as tasks, that require thread blocking. What I try to say, is that back in old days application had to divide long tasks into small pieces and constantly return control to OS, so other applications wouldn't be locked. Funny thing, but even for hardware multitasking - it's still the best way of doing things. That's why applications still use exactly the same message-based system, as back in 3.0/3.1 days, instead of being constantly active and relying on hardware multitasking to sort things out. You just can't terminate thread at any moment, as it's the same, as terminating process via Task Manager - some objects would be in undefined state in this case. You have to exit thread procedure in order to terminate it properly. So you still need to divide your task into small pieces and constantly check, if Terminated property isn't True and exit thread, when it's the case - not rely on OS, i.e. just execute and terminate thread, when you want.

Best solution: to have some worker thread pool, to divide your long tasks into small pieces and send them to thread manager, that will assign them to worker threads and process one by one. But if it's way too hard for you - try to execute every task in separate thread, but divide it into smaller task and constantly check, if this task isn't abandoned. Second variant isn't good in common case, cuz it can cause number of simultaneous threads inflation, that is bad thing, as OS core would struggle in this case.
« Last Edit: August 07, 2018, 02:20:16 pm by Mr.Madguy »
Is it healthy for project not to have regular stable releases?
Just for fun: Code::Blocks, GCC 13 and DOS - is it possible?

CM630

  • Hero Member
  • *****
  • Posts: 1091
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Terminating a subroutine without multithreading?
« Reply #14 on: August 30, 2018, 03:31:13 pm »

I have a check if Assigned(LImThread)=true then  LImThread.Terminate; but is occurs that Assigned(LImThread) always returns True.

In the end of my thread I had:
Code: Pascal  [Select][+][-]
  1.   Writeln ('TLoadImageThread: Self.Free');
  2.   Self.Free;
  3.  

So I ammended the code to become
Code: Pascal  [Select][+][-]
  1.   Writeln ('TLoadImageThread: Self.Free');
  2.   Self.Free;
  3.   Writeln ('TLoadImageThread: Self.Nil');
  4.   Self:=nil;
  5.   if Assigned(LImThread) then DebugPrint('!!!! Limthread is NOT NIL') else DebugPrint('!!!! Limthread is NIL');
  6.  
Code after Self.Free; is not executed. No surprise.

Then I commented Self.Free; so code became
Code: Pascal  [Select][+][-]
  1.   {Writeln ('TLoadImageThread: Self.Free');
  2.   Self.Free;}
  3.   Writeln ('TLoadImageThread: Self.Nil');
  4.   Self:=nil;
  5.   if Assigned(LImThread) then DebugPrint('!!!! Limthread is NOT NIL') else DebugPrint('!!!! Limthread is NIL');
  6.  
But I still get !!!! Limthread is NOT NIL.
Shall I use an extra variable to detect if thread is running? Or is there a better way?
Лазар 3,2 32 bit (sometimes 64 bit); FPC3,2,2; rev: Lazarus_3_0 on Win10 64bit.

 

TinyPortal © 2005-2018