Threads - Self Terminating?

Everything else that doesn't fall into one of the other PB categories.
dmoc
Enthusiast
Enthusiast
Posts: 739
Joined: Sat Apr 26, 2003 12:40 am

Threads - Self Terminating?

Post by dmoc »

Win98 - If a thread-based procedure completes it's task and exits normally (or via a ProcedureReturn) shouldn't the thread itself be deleted? I'm talking about the thread/s as reported by a process monitoring utility. As far as PB is concerned everything appears ok but if your prog keeps launching threads then the number of threads reported by the system just keeps increasing. They *do* get cleaned out when the prog exits but this is no good for a prog that is intended to run continuously. I'm trying to avoid KillThread.
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

...,

Threads do not close alone, and you have to be careful to clean by yourself if you write a prog running threads, otherwise it may be some memory not freed.

Depending on the application you have, it is also possible that you run many threads in a high number so that the processor may hang because of priority management issues.

Rgrds
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
dmoc
Enthusiast
Enthusiast
Posts: 739
Joined: Sat Apr 26, 2003 12:40 am

Post by dmoc »

Thanks for the info. So if the proc itself has terminated using KillThread() is safe?
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

... it should be !

I have noticed that it is not so sure.

When running an app using threads, if you use strings, which is a well known problem, I have had some head ache because the main program may end before threads are really terminated. I don't know how to make it really stable.

So, you have to register all threads you run, and manage your app so that you are sure what runs, and what ends, keeping the control in the main code.

I use to register by using either a linked list or an array, keeping the thread's ID until it ends. When a given thread ends, it cancels its instance in the array, so that the main code can know, what still runs or not.

And so on ...
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
dmoc
Enthusiast
Enthusiast
Posts: 739
Joined: Sat Apr 26, 2003 12:40 am

Post by dmoc »

My threads avoid strings and only do the bare minimum required. Everything else is done in main code (I try hard to minimise headaches :P ).

I'm not being lazy here, of course I have tried various things but I have noticed that getting something to work doesn't mean that it will work over an extended period, eg, that 1/1000000 chance of a hick-up that causes your code to hang :? Anyway, thanks again.
dmoc
Enthusiast
Enthusiast
Posts: 739
Joined: Sat Apr 26, 2003 12:40 am

Post by dmoc »

Here's some code which shows my problem. No matter what I try the threads remain until the program (compiled on PB v3.81) actually quits. Any/all suggestions appreciated.

Code: Select all

; Monitored using: Process Explorer v8.20 (www.sysinternals.com)

Global n.l, q.l ; (n)umber of threads to run, (q)uit flag
Dim tid.l(10) ; Thread ID's
Dim tff.l(10) ; Thread Finished Flags

Procedure dumdedum(d.l)
  Shared q.l
  Delay(d): q=1 ; Delay then set quit flag
EndProcedure

Procedure athread(tn.l)
  Delay(2000+Random(3)*1000) ; 2..5 secs delay
  tff(tn)=1 ; Finished Flag
  ;KillThread(tid(n))
EndProcedure

; Start some threads
n=3 ; Number of threads to start
For i=1 To n: tid(i)=CreateThread(@athread(),i): Next

CreateThread(@dumdedum(),10000) ; WatchDog thread

; Monitor threads...
Repeat
  Delay(500)
  c=0
  For i=1 To n
    If tff(i)=1: c+1: EndIf
  Next
  If q: Debug "time-out": Break: EndIf
  If c=n: Debug "all-finished": Break: EndIf
ForEver

Debug "Still see the threads? 4 secs to check!"
Delay(4000) ; 4 sec while you check

; Now try explicit kill/ terminate...

For i=1 To n: If tid(i): KillThread(tid(i)): EndIf : Next
Debug "How about now? 4 secs to check!"
Delay(4000) ; 4 sec while you check

For i=1 To n: If tid(i): TerminateThread_(tid(i),0): EndIf : Next
Debug "Don't tell me they are still there!? 4 secs to check!"
Delay(4000) ; 4 sec while you check

End
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

dmoc,

This is the way I would do :

Code: Select all

#NThreads = 10

Dim ThreadIDs.l(#NThreads)

Procedure athread(ThisThreadID.l)
  Delay(2000+Random(3)*1000)
  ThreadIDs(ThisThreadID) = 0
EndProcedure 

Procedure.l WatchThreads()
  Remains.l = 0
  For i.l = 1 To #NThreads
    If ThreadIDs(i) <> 0
        Remains + 1
    EndIf
  Next
  ProcedureReturn Remains
EndProcedure

  n= 10 ; Number of threads to start 
  For i=1 To #NThreads
    ThreadIDs(i)=CreateThread(@athread(),i)
  Next 

  Repeat
    Remaining.l = WatchThreads()
    Debug "@ " + FormatDate("%hh:%ii:%ss", Date()) + " remains " + Str(Remaining) + " threads"
    Delay(1000)
  Until Remaining = 0
    
End
Seems to work ... tell me about results with this code on your side.

Rgrds
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
dmoc
Enthusiast
Enthusiast
Posts: 739
Joined: Sat Apr 26, 2003 12:40 am

Post by dmoc »

Ah, maybe I haven't explained myself clearly: as far as PB code is concerned the threads have terminated, at least as far as you can tell from monitoring your own state vars, but using a process monitor utility (like SysInternal's "Process Explorer") the threads are definately still listed in the process table (or whatever). To see this add a delay to the end of the program to give you time to switch to the process monitor. If a program really is terminating then it's not a problem but my program is continually firing one-shot threads which when exited/ killed/ terminated *still* remain. So the thread count according to system resources just continues increasing! See my problem?
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

I don't know really the way to ensure which is right and which is wrong.

By experience, I know that threads are really ended if the internal app monitoring tells so. And the allocated emory is freed also.

Using an external monitor does not give me more reults than what I see on the task manager.

When I did real tests, I was playing with usually 200- 1.000 threads for networking stuff, and I am sure whether threads release or not.

Well, ... can't tell more.
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
dmoc
Enthusiast
Enthusiast
Posts: 739
Joined: Sat Apr 26, 2003 12:40 am

Post by dmoc »

Thanks for your help anyway. I did a google and came up with the following page...

viewtopic.php?t=6146&view=next

...yeah, right back here (funny I couldn't see it when I searched the forums). Turns out that "CloseHandle_(tid(i))" is preferable to other commands. I tried it and it seemed to do the job. I say "seemed" because with my quick test one or two threads were left over. Tomorrow I'm going to test with more threads and and see how it performs.
fweil
Enthusiast
Enthusiast
Posts: 725
Joined: Thu Apr 22, 2004 5:56 pm
Location: France
Contact:

Post by fweil »

Well,

Give us feedback then ...

Rgrds
My avatar is a small copy of the 4x1.8m image I created and exposed at 'Le salon international du meuble à Paris' january 2004 in Matt Sindall's 'Shades' designers exhibition. The original laminated print was designed using a 150 dpi printout.
dmoc
Enthusiast
Enthusiast
Posts: 739
Joined: Sat Apr 26, 2003 12:40 am

Post by dmoc »

Silly me, forgot about the stuff detailed near the end of this MS page...

http://msdn.microsoft.com/library/defau ... hreads.asp

...although I did think PB handled this itself.
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

I do this sorta thing

Code: Select all

Global QuitEvent.l
QuitEvent=CreateEvent_(#Null,#True,#False,"MyQuitEvent")

Procedure ThreadProc(x)
  Repeat
    Debug x
  Until WaitForSingleObject_(QuitEvent,0)=0
  Debug "Exit>"+Str(x)
EndProcedure

Dim hThread(10)
For x=1 To 10
  hThread(x)=CreateThread(@ThreadProc(),x)
Next

Delay(1000)

SetEvent_(QuitEvent)

For x=1 To 10
  WaitThread(hThread(x))
Next

Debug "All Threads Finished..."
Or you could use my ThreadSync library... :D
dmoc
Enthusiast
Enthusiast
Posts: 739
Joined: Sat Apr 26, 2003 12:40 am

Post by dmoc »

PolyVector, I like your library but my only problem is getting rid of them once they are finished (with the prog still running, as it should be). I found the reason and it's because win98 still maintains an entry for a finished thread so it's exit code can be queried. Once all handles to a particular thread are freed then even this disappears. I don't think PB closes thread handles until the program itself exits.

fweil, update soon :D
dmoc
Enthusiast
Enthusiast
Posts: 739
Joined: Sat Apr 26, 2003 12:40 am

Post by dmoc »

I've tried it a number of times with a varying number of threads and CloseHandle_() seems to reliably purge thread leftovers. So I'm a happy chappy :D But of course one thing leads to another and I wonder now how you can tell if a thread is still alive without keeping your own flags. Seems a reasonable request so I looked for a win32 function and can't find one. The nearest I see is GetThreadTimes_() but the key bit of info "lpExitTime" (a FILETIME structure) is undefined if the thread has not exited :roll: You'd think it would at least be a null ptr. Not to worry though, it's not a problem for me.
Post Reply