Skipping examples:
Click on any menu item and hold before selecting and the thread cranks along as it should, but the gui event loop loses track of the thread messages.
Hit the [Escape] key at various points. You will see the 1st resume occurs at 2 skips and later resumes only 1 skip?
Thanks to mk-soft for his example code.
Code: Select all
; http://www.purebasic.fr/english/viewtopic.php?f=12&t=64084&hilit=simple+thread+control
; Comment: Simple Thread Control
; Author: mk-soft
; Version: v1.03
; Create: 22.11.2015
; Update: 01.09.2016
; Update: 20170816, mangled by skywalk
;==================================================================================
; COMPILER OPTIONS:
; [ ] Use Compiler: PureBasic 5.6 (x64)
; [ ] Use Icon:
; [ ] Enable inline ASM support
; [x] Create threadsafe executable
; [ ] Enable OnError lines support
; [x] Enable XP skin support
; [ ] Request Administrator mode for Windows Vista
; [ ] Request User mode for Windows Vista (no virtualization)
; Library Subsystem:
; Executable Format: Windows ;|Console|Shared DLL
; CPU: All ;|Dynamic|w/MMX|w/3DNOW|w/SSE|w/SSE2
; File Format: UTF-8
;==================================================================================
EnableExplicit
Enumeration #PB_Event_FirstCustomValue
#thr_event_state
EndEnumeration
Enumeration
#thr_cmd_nothing = 0
#thr_cmd_start
#thr_cmd_pause
#thr_cmd_continue
#thr_cmd_stop
#thr_now_nothing = 0
#thr_now_running
#thr_now_paused
#thr_now_continued
#thr_now_stopped
#thr_now_finished
;-Thread data
#thr_dat_none = 0
#thr_dat_new ; signal new data available.
EndEnumeration
Structure thread_INFO
n.i
h.i
sig.i
cmd.i
now.i
; data
dat.i
nPts.i
gadStb.i
EndStructure
Global thr1.thread_INFO
;//////////////////////////////////////////////////////////////////
; GUI elements
Enumeration
#gadStart = 0
#gadPause
#gadStop
#gadEdr
#gadStb = 0
EndEnumeration
; Global data structure
Structure myData_INFO
nPts.l
name$
EndStructure
Global myD.myData_INFO
;-{ PROCEDURES
Procedure thr_Do(*me.thread_INFO)
Protected.i i
Protected.d x
Debug "Thread started at nPts = " + Str(myD\nPts)
*me\sig = CreateSemaphore(1)
Repeat
Select *me\cmd
Case #thr_cmd_start
*me\cmd = #thr_cmd_nothing
If *me\now <= #thr_now_nothing Or *me\now >= #thr_now_finished
*me\now = #thr_now_running
*me\dat = #thr_dat_none
PostEvent(#thr_event_state, 0, *me, *me\now)
;Delay(30)
EndIf
Case #thr_cmd_pause
*me\cmd = #thr_cmd_nothing
If *me\now = #thr_now_running
Debug "Thread paused at nPts = " + Str(myD\nPts)
*me\now = #thr_now_paused
PostEvent(#thr_event_state, 0, *me, *me\now)
;Delay(30)
EndIf
Case #thr_cmd_continue
*me\cmd = #thr_cmd_nothing
If *me\now = #thr_now_paused
Debug "Thread resumed at nPts = " + Str(myD\nPts)
*me\now = #thr_now_running
PostEvent(#thr_event_state, 0, *me, *me\now)
;Delay(30)
EndIf
Case #thr_cmd_stop
*me\cmd = #thr_cmd_nothing
If *me\now < #thr_now_stopped
Debug "Thread stopped at nPts = " + Str(myD\nPts)
*me\now = #thr_now_stopped
PostEvent(#thr_event_state, 0, *me, *me\now)
;Delay(30)
EndIf
EndSelect
If *me\now = #thr_now_paused Or *me\now = #thr_now_nothing
WaitSemaphore(*me\sig)
ElseIf *me\now = #thr_now_stopped
Break
EndIf
;////////////////////////////////////////////////////////////
; Simulate some working thread code...
For i = 0 To 1e6
x = Cos(i) * Sin(i)
Next i
myD\nPts + 1
OpenFile(99, #PB_Compiler_FilePath + "z.txt", #PB_File_Append)
WriteStringN(99, "Finished -> " + RSet(Str(myD\nPts), 10), #PB_Ascii)
CloseFile(99)
*me\dat = #thr_dat_new
PostEvent(#thr_event_state, 0, *me, *me\now)
;////////////////////////////////////////////////////////////
Until *me\now = #thr_now_stopped
Debug "Thread released at nPts = " + Str(myD\nPts)
*me\now = #thr_now_finished
PostEvent(#thr_event_state, 0, *me, *me\now)
; Release thread
FreeSemaphore(*me\sig)
*me\sig = 0
EndProcedure
;-} PROCEDURES
;-{ TEST
CompilerIf 1
Procedure Main()
Protected.i evWW, evM
Protected.s r$
If OpenWindow(0, #PB_Any, #PB_Any, 600, 400, "Thread Control+", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget)
CreateStatusBar(#gadStb, WindowID(0))
AddStatusBarField(1000)
ButtonGadget(#gadStart, 10, 10, 120, 25, "Start")
ButtonGadget(#gadPause, 140, 10, 120, 25, "Pause/Resume")
ButtonGadget(#gadStop, 400, 10, 120, 25, "Stop")
EditorGadget(#gadEdr, 10, 40, WindowWidth(0)-20, WindowHeight(0)-MenuHeight()-StatusBarHeight(#gadStb)-25-20)
If CreateMenu(0, WindowID(0))
MenuTitle("File")
MenuItem(1, "&Load...")
MenuItem(2, "Save")
MenuItem(3, "Save As...")
MenuBar()
MenuItem(5, "&Quit")
MenuTitle("Thread")
MenuItem(7, "Start")
MenuItem(8, "Pause/Resume")
MenuItem(9, "Stop")
EndIf
AddKeyboardShortcut(0, #PB_Shortcut_Escape, 8)
AddKeyboardShortcut(0, #PB_Shortcut_Control | #PB_Shortcut_Q, 5)
thr1\gadStb = #gadStb
Repeat
Select WaitWindowEvent()
Case #PB_Event_Menu
evM = EventMenu()
Select evM
Case 5
Break
Case 7
If Not IsThread(thr1\n)
thr1\n = CreateThread(@thr_Do(), @thr1)
EndIf
thr1\cmd = #thr_cmd_start
If thr1\sig
SignalSemaphore(thr1\sig)
EndIf
Case 8 ; Pause/Resume
If thr1\now = #thr_now_running
thr1\cmd = #thr_cmd_pause
Debug "Paused"
ElseIf thr1\now = #thr_now_paused
thr1\cmd = #thr_cmd_continue
If thr1\sig
SignalSemaphore(thr1\sig)
EndIf
Debug "Resumed"
EndIf
Case 9 ; Stop
Debug "Stop"
thr1\cmd = #thr_cmd_stop
If thr1\sig
SignalSemaphore(thr1\sig)
EndIf
EndSelect
Case #thr_event_state
Select thr1\now
Case #thr_now_nothing
StatusBarText(thr1\gadStb, 0, "Nothing")
Case #thr_now_running
If thr1\dat = #thr_dat_new
thr1\dat = #thr_dat_none
r$ = "Finished -> " + RSet(Str(myD\nPts), 10)
AddGadgetItem(#gadEdr, -1, r$)
SendMessage_(GadgetID(#gadEdr), #EM_SETSEL, -1, -1) ; Scroll to bottom.
SetGadgetText(#gadPause, "Pause")
StatusBarText(thr1\gadStb, 0, "Running")
EndIf
Case #thr_now_paused
SetGadgetText(#gadPause, "Resume")
StatusBarText(thr1\gadStb, 0, "Paused")
Case #thr_now_continued
SetGadgetText(#gadPause, "Pause")
StatusBarText(thr1\gadStb, 0, "Resumed")
Case #thr_now_stopped
StatusBarText(thr1\gadStb, 0, "Stopped")
Case #thr_now_finished
StatusBarText(thr1\gadStb, 0, "Finished")
;WaitThread(thr1\n, 3000)
;KillThread(thr1\n)
thr1\n = 0
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case #gadStart
If Not IsThread(thr1\n)
thr1\n = CreateThread(@thr_Do(), @thr1)
EndIf
thr1\cmd = #thr_cmd_start
If thr1\sig
SignalSemaphore(thr1\sig)
EndIf
Case #gadPause
If thr1\now = #thr_now_running
thr1\cmd = #thr_cmd_pause
ElseIf thr1\now = #thr_now_paused
thr1\cmd = #thr_cmd_continue
If thr1\sig
SignalSemaphore(thr1\sig)
EndIf
EndIf
Case #gadStop
thr1\cmd = #thr_cmd_stop
If thr1\sig
SignalSemaphore(thr1\sig)
EndIf
EndSelect
Case #PB_Event_CloseWindow
Break
EndSelect
ForEver
EndIf
EndProcedure
Main()
CompilerEndIf
;-} TEST