Page 1 of 1

Block on END

Posted: Mon Jul 24, 2023 10:32 am
by ALAN-MHz
Dear all, i've a strange problem on a software compiled with latest v6.02 LTS, sometimes do not close on end remain process blocked, to better explain is a window that on event show a messagerequester for confirm to close, if user confirm the command "end" is called, i've also tried to free all resources before calling "end", i've also tried to insert a "calldebugger" before the end to better check, calldebugger is called and when i step on "end" program do not close also in IDE and i cannot pause it, is completely locked.

The problem is also randomic in both compiled and in IDE, sometimes software close without problem, sometimes i've got this problem

Of couse killing from task manager resolve the problem.

Any ideas ?

Re: Block on END

Posted: Mon Jul 24, 2023 11:24 am
by jacdelad
Me trying to help you without any hint of code:
Image

Re: Block on END

Posted: Mon Jul 24, 2023 11:28 am
by mk-soft
Which operating system.
macOS and Linux do not like it when threads are still running in the background.

Re: Block on END

Posted: Mon Jul 24, 2023 11:57 am
by ALAN-MHz
Windows 11

Code: Select all

    If MessageRequester ( Softname , "Sure to close ?" , #PB_MessageRequester_YesNo ) = #PB_MessageRequester_Yes
     If IsThread ( CleanThread )
      KillThread ( CleanThread )
     EndIf
     If IsThread ( AutoPilotThread )
      KillThread ( AutoPilotThread )
     EndIf
     If IsThread ( AutoRetryThread )
      KillThread ( AutoRetryThread )
     EndIf
     UpdateDB ()
     UpdateFile ()
     If IsDatabase ( 0 )
      CloseDatabase ( 0 )
     EndIf
     If IsDatabase ( 1 )
      CloseDatabase ( 1 )
     EndIf
     Delay ( 1000 )
     ReleaseMutex_ ( Mutex )
     End
    EndIf

Re: Block on END

Posted: Mon Jul 24, 2023 2:44 pm
by jacdelad
Don't use KillThread, instead set a global variable or something and handle it within the thread!
Also, your code isn't runnable.

Re: Block on END

Posted: Mon Jul 24, 2023 3:03 pm
by ALAN-MHz
jacdelad wrote: Mon Jul 24, 2023 2:44 pm Don't use KillThread, instead set a global variable or something and handle it within the thread!
Also, your code isn't runnable.
i cannot use global variable to manage the thread because they are totally indipendent from main code and contain a lot of delay for processing jobs scheduled, if i set a variable for inform the thread that must end without kill i need to wait the last delay that is currently running in the thread, for example if sleep is 1 minute so the main window must wait 1 minute to close and this is totally unacceptable.

My code isn't runnable but work perfectly except the program end ? really interesting, so explain me what's wrong

Re: Block on END

Posted: Mon Jul 24, 2023 3:13 pm
by mk-soft
Build a loop with 100ms delay and query the end of the programm in this loop.

Where is a owner of Mutex ?
MSDN:
Remarks
The ReleaseMutex function fails if the calling thread does not own the mutex object.
A thread obtains ownership of a mutex either by creating it with the bInitialOwner parameter set to TRUE or by specifying its handle in a call to one of the wait functions. When the thread no longer needs to own the mutex object, it calls the ReleaseMutex function so that another thread can acquire ownership.
A thread can specify a mutex that it already owns in a call to one of the wait functions without blocking its execution. This prevents a thread from deadlocking itself while waiting for a mutex that it already owns. However, to release its ownership, the thread must call ReleaseMutex one time for each time that it obtained ownership (either through CreateMutex or a wait function).

Re: Block on END

Posted: Mon Jul 24, 2023 3:50 pm
by ALAN-MHz
it's the main thread that initialize the mutex after the global variable declaration

do you think that thread can cause the end failure ?

it's also strange that also the debugger freeze

testing:

Code: Select all

    If MessageRequester ( Softname , "Sure to close ?" , #PB_MessageRequester_YesNo ) = #PB_MessageRequester_Yes
     CloseThread = #True
     Repeat
      Delay ( 100 )
     Until IsThread ( CleanThread ) = 0 And IsThread ( AutoPilotThread ) = 0 And IsThread ( AutoRetryThread ) = 0
     UpdateDB ()
     UpdateFile ()
     If IsDatabase ( 0 )
      CloseDatabase ( 0 )
     EndIf
     If IsDatabase ( 1 )
      CloseDatabase ( 1 )
     EndIf
     ReleaseMutex_ ( Mutex )
     CallDebugger
     End
    EndIf

Re: Block on END

Posted: Mon Jul 24, 2023 3:59 pm
by jacdelad
ALAN-MHz wrote: Mon Jul 24, 2023 3:03 pm
jacdelad wrote: Mon Jul 24, 2023 2:44 pm Don't use KillThread, instead set a global variable or something and handle it within the thread!
Also, your code isn't runnable.
i cannot use global variable to manage the thread because they are totally indipendent from main code and contain a lot of delay for processing jobs scheduled, if i set a variable for inform the thread that must end without kill i need to wait the last delay that is currently running in the thread, for example if sleep is 1 minute so the main window must wait 1 minute to close and this is totally unacceptable.

My code isn't runnable but work perfectly except the program end ? really interesting, so explain me what's wrong
But that's the way it will work. Also, you can chop your long delay into shorter delays (and process the rest of your stuff after n-count of processed delays) to be able to process the termination variable.

Re: Block on END

Posted: Mon Jul 24, 2023 8:01 pm
by mk-soft
But not the loop when the program ends, but in the thread.

Code: Select all

;-TOP

CompilerIf Not #PB_Compiler_Thread
  CompilerError "Use Compiler Option ThreadSafe"
CompilerEndIf

#ProgramTitle = "Main Window"
#ProgramVersion = "v1.01.2"

Enumeration Windows
  #Main
EndEnumeration

Enumeration MenuBar
  #MainMenu
EndEnumeration

Enumeration MenuItems
  #MainMenuAbout
  #MainMenuExit
EndEnumeration

Enumeration Gadgets
  #MainList
EndEnumeration

Enumeration StatusBar
  #MainStatusBar
EndEnumeration

; ----

Structure udtMyThread
  ThreadID.i
  Exit.i
  Name.s
  Pause.i
EndStructure

Global.udtMyThread th1, th2

Procedure MyThread(*Data.udtMyThread)
  Protected time
  With *Data
    Debug "Init Thread " + \Name
    Repeat
      ; Working
      Debug "Do any ... " + \Name
      For i = 1 To 100
        ; Check exit
        If \Exit
          Debug "Cancel Thread " + \Name
          Break
        EndIf
        ; Simulate processing
        Delay(8)
      Next
      ; Pause
      time = ElapsedMilliseconds()
      Repeat
        ; Check exit
        If \Exit
          Break 2
        EndIf
        Delay(100)
        If ElapsedMilliseconds() - time > \Pause
          Break
        EndIf
      ForEver
    ForEver
    Debug "Exit Thread " + \Name
  EndWith
EndProcedure

; ----

Procedure UpdateWindow()
  Protected dx, dy
  dx = WindowWidth(#Main)
  dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
  ; Resize gadgets
  ResizeGadget(#MainList, 0, 0, dx, dy)
EndProcedure

Procedure Main()
  Protected dx, dy
  
  #MainStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
  
  If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 800, 600, #ProgramTitle , #MainStyle)
    ; Menu
    CreateMenu(#MainMenu, WindowID(#Main))
    MenuTitle("&File")
    CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
      MenuItem(#PB_Menu_About, "")
    CompilerElse
      MenuItem(#MainMenuAbout, "About")
    CompilerEndIf
    ; Menu File Items
    
    CompilerIf Not #PB_Compiler_OS = #PB_OS_MacOS
      MenuBar()
      MenuItem(#MainMenuExit, "E&xit")
    CompilerEndIf
    
    ; StatusBar
    CreateStatusBar(#MainStatusBar, WindowID(#Main))
    AddStatusBarField(#PB_Ignore)
    
    ; Gadgets
    dx = WindowWidth(#Main)
    dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
    ListViewGadget(#MainList, 0, 0, dx, dy)
    
    ; Bind Events
    BindEvent(#PB_Event_SizeWindow, @UpdateWindow(), #Main)
    
    th1\Name = "MyThread 1"
    th1\Pause = 5000
    th1\ThreadID = CreateThread(@MyThread(), @th1)
    Delay(100)
    th2\Name = "MyThread 2"
    th2\Pause = 7500
    th2\ThreadID = CreateThread(@MyThread(), @th2)
    
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Select EventWindow()
            Case #Main
              Break
              
          EndSelect
          
        Case #PB_Event_Menu
          Select EventMenu()
            CompilerIf #PB_Compiler_OS = #PB_OS_MacOS   
              Case #PB_Menu_About
                PostEvent(#PB_Event_Menu, #Main, #MainMenuAbout)
                
              Case #PB_Menu_Preferences
                
              Case #PB_Menu_Quit
                PostEvent(#PB_Event_CloseWindow, #Main, #Null)
                
            CompilerEndIf
              
            Case #MainMenuExit
              PostEvent(#PB_Event_CloseWindow, #Main, #Null)
              
            Case #MainMenuAbout
              MessageRequester("About", #ProgramTitle + #LF$ + #ProgramVersion, #PB_MessageRequester_Info)
              
          EndSelect
          
          
        Case #PB_Event_Gadget
          Select EventGadget()
            Case #MainList
              Select EventType()
                Case #PB_EventType_Change
                  ;
              EndSelect
              
          EndSelect
          
      EndSelect
    ForEver
    
    th1\Exit = #True
    th2\Exit = #True
    If WaitThread(th1\ThreadID, 5000) = 0
      KillThread(th1\ThreadID)
      Debug "Thread th1 killed"
    EndIf
    If WaitThread(th2\ThreadID, 5000) = 0
      KillThread(th2\ThreadID)
      Debug "Thread th2 killed"
    EndIf
    
  EndIf
  
EndProcedure : Main()

Re: Block on END

Posted: Mon Jul 24, 2023 9:59 pm
by BarryG
jacdelad wrote: Mon Jul 24, 2023 2:44 pmDon't use KillThread, instead set a global variable or something and handle it within the thread
That won't help when a thread is showing a MessageRequester() or InputRequester(), etc. KillThread() is needed in such cases.

Re: Block on END

Posted: Tue Jul 25, 2023 7:07 am
by ALAN-MHz
threads seems more stable with a global variable for closing them, i test more and more times to be sure because as told the problem is randomic

thanks to all for suggestions