This library allows to pass object data to the worker instance (referred to as worker thread now). The worker thread can report its progress back to the main thread, and both can pause/resume/stop the worker thread, optionally with an arbitrary argument (e.g. a reason, can be an object). Arbitrary data can be send between the threads while the worker thread is running. If desired, the worker thread can stay running and wait for new tasks so it doesn't need to start again if a new task needs to be executed (memory usage vs. speed). The library uses event handlers (thanks IsNull!) and Serialization (thanks infogulch for LSON!).
Here's a simple example:
#SingleInstance, off ;required for obvious reasons ;This function needs to be called in the Autoexecute section so this instance ;can possibly turn into a worker thread. The worker thread stays in this function during its runtime. InitWorkerThread() ;Main thread continues here ;Create the worker thread! WorkerThread := new CWorkerThread("WorkerFunction", 0, 1, 1) ;Setup event handlers for the main thread WorkerThread.OnStop.Handler := "OnStoppedByWorker" WorkerThread.OnProgress.Handler := "ProgressHandler" WorkerThread.OnFinish.Handler := "OnFinish" ;Start the worker thread WorkerThread.Start("A Parameter") return ;The functions below are event handlers of the main thread. They were specified above. OnStoppedByWorker(WorkerThread, Result) { Msgbox Error in worker thread! %Result% ExitApp } OnFinish(WorkerThread, Result) { MsgBox Worker thread completed successfully! %Result% ExitApp } ;Progress is a numeric integer value ProgressHandler(WorkerThread, Progress) { Tooltip, Progress: %Progress% } ;This is the main worker function that is executed in the worker thread. ;The thread will exit shortly after this function returns. ;This function may have a many parameters as desired, but they need to be specified during the worker thread creation. WorkerFunction(WorkerThread, Param) { ;This is a suggested structure for a worker thread that uses a loop. ;It properly accounts for state changes (which can be caused by the main thread or this thread) while(A_Index <= 100 && WorkerThread.State = "Running") { Sleep 100 ;This simulates work that takes some time WorkerThread.Progress := A_Index ;Report the progress of the worker thread. ;Lets allow this thread to randomly fail! Random, r, 1, 200 if(r = 1) WorkerThread.Stop("Error: " r) ;Pass the error value to the main thread } ;the return value of this function is only used when the worker thread wasn't stopped. return r } #include <WorkerThread>And here's a detailed usage example:
#SingleInstance, off ;required for obvious reasons ;This function needs to be called in the Autoexecute section so this instance ;can possibly turn into a worker thread. The worker thread stays in this function during its runtime. InitWorkerThread() ;Main thread continues here Gui, Add, Progress, vProgressBar w400, 0 Gui, Add, Button, vMainStart gMainStart y+10, Start Gui, Add, Button, vMainPause gMainPause x+10 w50 Disabled, Pause Gui, Add, Button, vMainStop gMainStop x+10 Disabled, Stop Gui, Add, Button, vMainData gMainData x+10 Disabled, Send Data Gui, +LabelMainGUI Gui, Show ;Create the worker thread! It will be reused in this program to demonstrate the possibility ;If the last parameter is set to 0, the worker thread will stay running and wait for tasks WorkerThread := new CWorkerThread("WorkerFunction", 1, 1, 1) ;Setup event handlers for the main thread WorkerThread.OnPause.Handler := "OnPausedByWorker" WorkerThread.OnResume.Handler := "OnResumedByWorker" WorkerThread.OnStop.Handler := "OnStoppedByWorker" WorkerThread.OnData.Handler := "OnDataFromWorker" WorkerThread.OnProgress.Handler := "ProgressHandler" WorkerThread.OnFinish.Handler := "OnFinish" return MainGUIClose: if(WorkerThread.State = "Running" || WorkerThread.State = "Paused") WorkerThread.Stop("Main thread exit") ;Stop the worker thread if it is still running ExitApp ;The main thread can control the execution of the worker thread, demonstrated by the event handlers of the buttons below: MainStart: if(WorkerThread.State = "Stopped" || WorkerThread.State = "Finished") { WorkerThread.Start("A Parameter", "Another unused parameter") ;Starting works only when in stopped state. The progress is reset to zero. GuiControl, Disable, MainStart GuiControl, Enable, MainStop GuiControl, Enable, MainPause GuiControl, Enable, MainData Gui, Show,, Running } return MainPause: if(WorkerThread.State = "Paused") { WorkerThread.Resume() GuiControl, , MainPause, Pause Gui, Show,, Running } else if(WorkerThread.State = "Running") { WorkerThread.Pause() GuiControl, , MainPause, Resume Gui, Show,,Paused by main thread } return MainStop: if(WorkerThread.State = "Running" || WorkerThread.State = "Paused") { WorkerThread.Stop("Stop running, worker!") ;We can pass a reason for the stop to the worker thread GuiControl, Disable, MainStop GuiControl, Disable, MainPause GuiControl, Disable, MainData GuiControl, Enable, MainStart Gui, Show,,Stopped by main thread } return MainData: if(WorkerThread.State = "Running" || WorkerThread.State = "Paused") WorkerThread.SendData("Data from main thread") ;We can pass arbitrary data between the threads return ;The functions below are event handlers of the main thread. They were specified above. OnPausedByWorker(WorkerThread) { global MainPause GuiControl, ,MainPause, Resume Gui, Show,, Paused by worker thread } OnResumedByWorker(WorkerThread) { global MainPause GuiControl, ,MainPause, Pause Gui, Show,, Running } OnStoppedByWorker(WorkerThread, Result) { global GuiControl, Enable, MainStart GuiControl, Disable, MainPause GuiControl, Disable, MainStop GuiControl, Disable, MainData Gui, Show,, Stopped by worker thread! Result: %Result% } OnFinish(WorkerThread, Result) { global Gui, Show,, Finished! Result: %Result% GuiControl, Enable, MainStart GuiControl, Disable, MainPause GuiControl, Disable, MainStop GuiControl, Disable, MainData } OnDataFromWorker(WorkerThread, Data) { MsgBox Data from worker: %Data% } ;Progress is a numeric integer value ProgressHandler(WorkerThread, Progress) { global ProgressBar GuiControl, , ProgressBar, %Progress% } ;This is the main worker function that is executed in the worker thread. ;The thread will exit shortly after this function returns. ;This function may have a many parameters as desired, but they need to be specified during the worker thread creation. WorkerFunction(WorkerThread, Param) { global WorkerProgress, WorkerPause, WorkerStop, WorkerData ;We can set up some event handlers for the worker thread here ;so it can react to pause/resume/stop events coming from the main thread WorkerThread.OnPause.Handler := "OnPausedByMain" WorkerThread.OnResume.Handler := "OnResumedByMain" WorkerThread.OnStop.Handler := "OnStoppedByMain" WorkerThread.OnData.Handler := "OnDataFromMain" Gui, Add, Progress, vWorkerProgress w400, 0 Gui, Add, Button, vWorkerPause gWorkerPause w50, Pause Gui, Add, Button, vWorkerStop gWorkerStop x+10, Stop Gui, Add, Button, vWorkerData gWorkerData x+10, Send Data Gui, +LabelWorkerGUI Gui, Show,, Passed Parameter: %Param% ;This is a suggested structure for a worker thread that uses a loop. ;It properly accounts for state changes (which can be caused by the main thread or this thread) while(A_Index < 100 && WorkerThread.State = "Running") { GuiControl,,WorkerProgress, %A_Index% Sleep 40 ;This simulates work that takes some time WorkerThread.Progress := A_Index ;Report the progress of the worker thread. while(WorkerThread.State = "Paused") ;Optionally wait a while for resuming the worker thread. Sleep 10 } Gui, Destroy ;the return value of this function is only used when the worker thread wasn't stopped. return 42 } ;Prevent closing of the worker thread. Alternatively, the worker thread could stop itself. WorkerGUIClose: return ;The worker thread can control the execution of itself, demonstrated by the event handlers of the buttons below: WorkerPause: if(WorkerThread.State = "Paused") { WorkerThread.Resume() GuiControl, , WorkerPause, Pause } else if(WorkerThread.State = "Running") { WorkerThread.Pause() GuiControl, , WorkerPause, Resume } return WorkerStop: if(WorkerThread.State = "Running" || WorkerThread.State = "Paused") { WorkerThread.Stop(23) ;Parameter is passed back to main thread as result Gui, Destroy } return WorkerData: if(WorkerThread.State = "Running" || WorkerThread.State = "Paused") WorkerThread.SendData("Data from worker thread!") ;We can send arbitrary data between threads! return ;The functions below are event handlers of the worker thread. They were specified above. OnPausedByMain() { global WorkerPause GuiControl, , WorkerPause, Resume Gui, Show,, Paused by main thread } OnResumedByMain() { global WorkerPause GuiControl, , WorkerPause, Pause Gui, Show,, Running Worker thread } OnStoppedByMain(reason) { Msgbox Stopped by main thread! Reason: %reason% } OnDataFromMain(Data) { Msgbox Data from main thread: %Data% } #include <WorkerThread>The library (together with this example and the required dependencies can be found on GitHub.
Here's a direct link due to a request: <!-- m -->https://github.com/C.../zipball/master<!-- m -->