Announcement

Collapse
No announcement yet.

Thread Life

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Thread Life

    Playing with threads, which I don't use all that often ...

    I thought a thread would continue running after the main app closed, until the thread function itself ends. Not so in this example. What did I misunderstand?

    Code:
    Function PBMain() As Long
       Local hThread As Dword
       Thread Create MyThread(0) To hThread
       Thread Close hThread To hThread
       ? "Main Done"     '<--- without this thread does not run to completion
    
    Thread Function MyThread(ByVal x As Long) As Long
       Local i As Long
       For i = 1 To 1000000000   'about 2s
       Next i
       ? "Thread done"    '<---- never see this if PBMain is closed
    End Function

  • #2
    When the main thread ends all other threads owned by the process go bye bye.
    https://forum.powerbasic.com/forum/u...e-thread-close
    How long is an idea? Write it down.

    Comment


    • #3
      A way to wait for the thread to complete, from Help.

      But, I don't want the main app to stay alive. I'd like it to die but the thread continue.

      Code:
      Function PBMain() As Long
         Local hThread As Dword
         Thread Create MyThread(0) To hThread
         Thread Close hThread To hThread
      
         Do
            Sleep 100
         Loop While ThreadCount > 1
      
      End Function
      
      Thread Function MyThread(ByVal x As Long) As Long
         Local i As Long
         For i = 1 To 1000000000   'about 2s
         Next i
         ? "Thread done"
      End Function

      Comment


      • #4
        Thanks for the link Mike! I was surprised I couldn't find the information in Help.

        Comment


        • #5
          Do:sleep 50:loop until threadcount = 1
          How long is an idea? Write it down.

          Comment


          • #6
            When the main thread is finished its main job, don't let it close until any important threads it created are finished.

            Check out WaitForSingleObject and WaifForMultipleObjects

            Comment


            • #7
              '
              Code:
              GLOBAL gDone AS LONG
              
              #INCLUDE "win32api.inc"
              
              FUNCTION PBMAIN() AS LONG
              
               LOCAL hThread AS DWORD
               THREAD CREATE MyThread(0) TO hThread
              
               DO:SLEEP 50:LOOP UNTIL gDone 'this
               ? "Past waiting for gDone"
              
               DO:SLEEP 50:LOOP UNTIL THREADCOUNT = 1 'or this
               ? "Past threadcount"
              
               WaitForSingleObject hThread,%INFINITE  'or this
               ? "Past waitforsingleobject"
              
               THREAD CLOSE hThread TO hThread
               BEEP:SLEEP 300:BEEP
              
              END FUNCTION
              
              THREAD FUNCTION MyThread(BYVAL x AS LONG) AS LONG
               gDone = 1  'modified to before MSGBOX to signal Main Thread to finish   1:39 PM CST
               ? "Thread running, PBMAIN is waiting"
              END FUNCTION'
              How long is an idea? Write it down.

              Comment


              • #8
                Howdy, Mike and Paul!

                Here's the reason I bring this up.

                When creating index files in gbThreads, I may need to delete a folder of 50K files. Kill "*.*" works but that takes over a minute to complete. I might need to do that several times, so the minutes add up.

                I'd like it to take 0 seconds!

                So, an approach that works is to Name As the filled folder to something else, then MKDir the original folder. That takes no time at all and my main program can use the original folder name with no dead time.

                But, then I need to delete the renamed folder(s), which I can do with some background threads.

                But, the rub is that I may want to close the app, perhaps even restart it before the background tasks are completed.

                As we're discussing here, if I close the app, the threads die, leaving the background tasks unfinished. Yes, I know the easy answer is "don't to that"

                I could start another EXE, with no user interface, for each folder I want to delete in the background. But I was hoping I could create the running processes from the main app. If not threads, then what?

                Comment


                • #9
                  Howdy, Mike. Yep, thanks for the examples on how to wait for a thread(s) to complete before ending the app.

                  It's an additional 4th example, create an independent process without using an external EXE, and that continues after the main app is closed, that I think I'm looking for!

                  Comment


                  • #10
                    Perhaps create a batch file on the fly (just brainstorming?)
                    or
                    Start program with a batch file in a loop
                    Use exit codes to tell batch file to do whatever you want.
                    How long is an idea? Write it down.

                    Comment


                    • #11
                      Yep, Mike, a batch file would work, as would perhaps a command line to cover these two steps:

                      Code:
                      Kill DeadFolder$ + "*.*"
                      RmDir DeadFolder$

                      Comment


                      • #12
                        How about another program and use your favorite interprocess communication to request things.
                        The other process could use a thread for each required task.





                        How long is an idea? Write it down.

                        Comment


                        • #13
                          Mike, as I recall, the "&" symbol is used to put 2 commands on the same line, like this ...

                          Code:
                          iReturn& = Shell ("cmd /C del c:\users\gbeen\desktop\testb\*.* & Rmdir c:\users\gbeen\desktop\testb\")
                          ... added ... parentheses needed if the paths have spaces.

                          Comment


                          • #14
                            Ah, Bach! Shell execute to command line options.
                            I have never done with &. Have created batch files on the fly and shelled to them.
                            How long is an idea? Write it down.

                            Comment


                            • #15
                              Although, Mike, now that you make me think about it, the CMD RMDIR with /s switch will do it as well. In both case Window style 0 to hide what is happening.

                              Code:
                              iReturn = Shell ("cmd /C rmdir c:\users\gbeene\desktop\testb\ /s", 0)

                              Comment


                              • #16
                                and /Q I presume.
                                How long is an idea? Write it down.

                                Comment


                                • #17
                                  Ok, that came together nicely. I just tried the code below on a folder with 50K files. The folder is renamed, which happens instantly. Then MkDir re-creates the (empty) folder, ready to be used in the main app.

                                  The CMD stuff then continues to work in the background, even after my app closes, to delete the renamed folder containing the 50K files. That took about 30s on my PC.

                                  The advantages are that I can "delete" a folder with a lot of files with no apparent delay and re-use that folder in my app. I can also shut down my app without having to wait for the 50K files to be deleted.

                                  Code:
                                  'Compilable Example:
                                  #Compile Exe   "fastfolderkiller.exe"
                                  #Dim All
                                  %Unicode = 1
                                  #Include "Win32API.inc"
                                  
                                  Global NewFolder$, hThread As Dword
                                  
                                  Function PBMain() As Long
                                     FastFolderKiller("c:\users\gbeen\desktop\testB\")
                                     Beep
                                  End Function
                                  
                                  
                                  Function FastFolderKiller(Folder$) As Long
                                     Local iReturn As Long
                                  
                                     'valid string format
                                     Folder$ = Trim$(Folder$)                              'remove spaces on either end
                                     If Right$(Folder$,1) <> "\" Then Folder$ += "\"       'must have a trailing \
                                  
                                     'safety against deleting important folders
                                     If LCase$(Folder$) = "c:\program files\" Then Exit Function         'safety
                                     If LCase$(Folder$) = "c:\program files (x86)\" Then Exit Function   'safety
                                     If LCase$(Folder$) = "c:\windows\" Then Exit Function               'safety
                                     If LCase$(Folder$) = "c:\users\" Then Exit Function                 'safety
                                  
                                     'folder constraints
                                     If Dir$(Folder$ + "*.*", Only %SubDir) <> "" Then Exit Function   '(optional) has subfolders, which this function does not handle
                                     If IsFalse IsFolder(Folder$) Then Exit Function                   'not a folder
                                     If Dir$(Folder$ + "*.*") = "" Then RmDir Folder$ : Exit Function  'no files, so remove with RmDir. No further action required.
                                  
                                     NewFolder$ = NewFolderName                            'call function that gets a unique new folder name
                                     Name Folder$ As NewFolder$                            'get filled folder out of the way
                                     MkDir Folder$                                         'create an empty Folder$, as though it's files had been deleted
                                     iReturn = Shell ("cmd /C RmDir " + NewFolder$ + " /s/Q" , 0)  'background elimination of renamed/full folder
                                  End Function
                                  
                                  Function NewFolderName() As String
                                     'get next available folder name  "folder_being_killed_0000" through "folder_being_killed_9999"
                                     Local tempFolder$, i As Long
                                     For i = 0 To 9999
                                        tempFolder$ = "folder_being_killed_" + Format$(i,"0000") + "\"
                                        If IsFalse IsFolder(tempFolder$) Then Function = Exe.Path$ + tempFolder$ : Exit Function
                                     Next i
                                  End Function

                                  Comment


                                  • #18
                                    If Dir$(Folder$ + "*.*") = "" Then RmDir Folder$ : Exit Function 'no files, so remove with RmDir. No further action required.
                                    1. Why read when folder will be removed whether files are found or not, plus the following shell might be faster in the background.

                                    2. The line concatenates folder$ and also does a string comparison instead of using LEN = 0

                                    Trivial unless executed lots of times.









                                    How long is an idea? Write it down.

                                    Comment


                                    • #19
                                      Howdy, Mike!

                                      Why read ...
                                      Fewer steps plus no call to the NewFolderName Function, plus no call to Shell. Seemed like it was the less time consuming option.


                                      ...instead of using LEN..
                                      I had thought of that also, but didn't think a 1-char comparison would be any slower, particular for a empty string. Guess that calls for a test!

                                      Comment


                                      • #20
                                        Howdy Mike!

                                        Test results. Over 50K repeats, Not much different in this last test. However, I saw the numbers vary greatly. Generally, the LEN test was definitely faster by more than 20%. I'm not sure why there was so much variation in the results.

                                        Try the code below and see what you get. Or, see if you think the code isn't representative.


                                        Click image for larger version  Name:	pb_2208.jpg Views:	0 Size:	4.6 KB ID:	792330

                                        Code:
                                        #Include "win32api.inc"
                                        Function PBMain() As Long
                                           Local qFreq, qStart, qStop As Quad, temp$
                                           Local folder$, i As Long
                                           folder$ = "c:\pbwin10\"
                                           QueryPerformanceFrequency qFreq
                                              QueryPerformanceCounter qStart
                                              For i = 1 To 50000
                                                 If Len(Dir$(Folder$ + "*.*")) Then
                                                    'nothing
                                                 End If
                                              Next i
                                              QueryPerformanceCounter qStop
                                              temp$ = "LEN: " + Format$((qStop-qStart)/qFreq,"###.0") & " seconds"
                                        
                                              QueryPerformanceCounter qStart
                                              For i = 1 To 50000
                                                 If Dir$(Folder$ + "*.*") = "" Then
                                                    'nothing
                                                 End If
                                              Next i
                                              QueryPerformanceCounter qStop
                                              temp$ += $CrLf + $CrLf + "= Empty: " + Format$((qStop-qStart)/qFreq,"###.0") & " seconds"
                                        
                                              ? temp$
                                        End Function

                                        Comment

                                        Working...
                                        X