From dd91a1613821fc1f8f8ab5983a0c683f387e701f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 25 Oct 2020 01:18:31 +0000 Subject: [PATCH] Merge docs for 'Fixed threading and add shutdown control for threads via sleep' --- docs/scarpet/Full.md | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index 1fbefde5..0abae009 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -762,15 +762,15 @@ str('player at: %d %d %d',pos(player())) => 'player at: 567, -2423, 124' * * * ## Threading and Parallel Execution -Scarpet allows to run threads of execution in parallel to the main script execution thread. In Minecraft, the main -thread scripts are executed on the main server thread. Since Minecraft is inherently NOT thread safe, it is not that -beneficial to parallel execution in order to access world resources faster. Both `GetBlockState` and `setBlockState` +Scarpet allows to run threads of execution in parallel to the main script execution thread. In Minecraft, apps +are executed on the main server thread. Since Minecraft is inherently NOT thread safe, it is not that +beneficial to parallel execution in order to access world resources faster. Both `getBlockState` and `setBlockState` are not thread safe and require the execution to park on the server thread, where these requests can be executed in -the off-tick time in between ticks that didn't take 50ms. There are however benefits of running things in parallel, +the off-tick time in between ticks that didn't take all 50ms. There are however benefits of running things in parallel, like fine time control not relying on the tick clock, or running things independent on each other. You can still run your actions on tick-by-tick basis, either taking control of the execution using `game_tick()` API function -(nasty solution), or scheduling tick using `schedule()` function (much nicer solution), but threading often gives -the neatest solution to solve problems in parallel +(nasty solution), or scheduling tick using `schedule()` function (preffered solution), but threading gives much more control +on the timings without impacting the main game and is the only solution to solve problems in parallel (see [scarpet camera](/src/main/resources/assets/carpet/scripts/camera.sc)). Due to limitations with the game, there are some limits to the threading as well. You cannot for @@ -778,9 +778,11 @@ instance `join_task()` at all from the main script and server thread, because an function that require any world access, will require to park and join on the main thread to get world access, meaning that calling join on that task would inevitably lead to a typical deadlock. You can still join tasks from other threads, just because the only possibility of a deadlock in this case would come explicitly from your -bad code, not the internal world access behaviour. Some things tough like player or entity manipulation, can be +bad code, not the internal world access behaviour. Some things tough like players or entities manipulation, can be effectively parallelized. +If the app is shutting down, creating new tasks via `task` + ### `task(function, ... args)`, `task_thread(executor, function, ... args)` Creates and runs a parallel task, returning the handle to the task object. Task will return the return value of the @@ -799,6 +801,24 @@ a = 3; task_thread('temp', _(outer(a), b) -> foo(a,b), 5) => Another example of running the same thing passing arguments using closure over anonymous function as well as passing a parameter. +### `sleep()` `sleep(timeout)`, `sleep(timeout, close_call, ... args)` + + +Halts the execution of the thread (or the game itself, if run not as a part of a task) for `expr` milliseconds. +It checks for interrupted execution, in that case exits the thread (or the entire program, if not run on a thread) in case the app +is being stopped/removed. If the closing call is specified, executes the following function when a shutdown signal is triggered. +If run on the main thread (not as a taks) the call may only be invocated when the entire game shuts down, so close call only +makes sense for threads. For programs use `__on_close()` handler. + +Since `close_call` is executed after app shutdown is initiated, you won't be able to create new tasks in that block. Threads +should periodically call `sleep` to ensure all app tasks will finish when the app is closing or right after, but the app engine +will not forcefully remove your running tasks so the tasks themselves need to properly react to the closing request. + +
+sleep(50)  # wait for 50 milliseconds
+sleep(1000, _() -> print('Interrupted')) # waits for 1 second, outputs a message when thread is shut down.
+
+ ### `task_count(executor?)` If no argument provided, returns total number of tasks being executed in parallel at this moment using scarpet @@ -936,15 +956,6 @@ print('pi = '+pi) => prints: pi = 3.141592653589793 print(str('pi = %.2f',pi)) => prints: pi = 3.14 -### `sleep(expr)` - -Halts the execution of the program (and the game itself) for `expr` milliseconds. All in all, its better to -use `game_tick(expr)` to let the game do its job while the program waits - -
-sleep(50)
-
- ### `time()` Returns the number of milliseconds since 'some point', like Java's `System.nanoTime()`, which varies from system to