Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
api:thread:zh [2022/08/11 10:49]
fight_xing created
api:thread:zh [2023/10/20 13:20] (current)
hfsr [Thread Yield/Pull Without Blocking Example]
Line 1: Line 1:
-====== Thread API ======+====== Thread(线程) ​API ====== 
 +Thread(线程) API为OpenOS提供了协程的一种变体。线程比基础的协程在很多方面都更高级,并且对很多工作流程而言都更易用。OpenOS线程是自主的,非阻塞的,可分离的进程。
  
-**本篇文章部分/​全部内容还没有进行翻译**+* **自主性:**线程在创建后会立即开始异步执行,无需调用resume。与协程不同,线程在yield后会自恢复,且不会回到创建线程代码行。使用协程进行编程基于用户显式进行的协作yield和resume调用。然而,在线程中yield或调用`event.pull`,只会暂时阻塞线程,线程将自行继续运行
  
-The Thread API provides a variation of coroutines for openos. A thread is superior to basic coroutines in many ways and, for many workflows, is easier to work with. An openos thread is an autonomous non-blocking detachable process. 
  
-* **Autonomous**: Threads asynchronously begin execution immediately after creation without needing to call resume. Unlike coroutines, threads self-resume after yielding and do not yield back to the line of code where they were createdProgramming with coroutines builds on the cooperative yield and resume calls made explicitly by the user. Yielding or calling ​`event.pull` ​from a thread, however, only temporarily blocks just that thread and will continue on its own.+* **非阻塞性:**线程可以调用`computer.pullSignal`(或其更高级别的包装,如`event.pull`、`io.pull`等),而不会阻塞主内核进程或任何其他线程。当然线程本身会被阻塞,直到出现信号或超时。线程的计算流程与在命令行中运行相同的代码一样。在幕后,thread(线程)库使用`pullSignal`在线程之间切换,并在适当的时候唤醒线程。这与协程完全不同,在协程中,`computer.pullSignal`会阻塞系统上的所有其他活动,直到出现信号或超时。
  
  
-* **Non-Blocking**: Threads can call `computer.pullSignal` (or any higher level wrapper such as `event.pull`,​ `io.pull`, etc) without blocking the main kernel process nor any other thread. The thread itself is blocked until a signal or timeout occurs. The computational flow of the thread behaves just as if the same code were run in a script from the command line. Behind the scenes, the thread library is using pullSignal to swap between threads, and waking threads up when appropriate. This is very much unlike coroutines where `computer.pullSignal` blocks all other activity on the system until a signal or timeout occurs.+* **可分离性:**默认情况下,线程由创建它们的进程拥有(注意线程本身就是一个进程)。拥有线程的进程被称为其父进程。父进程关闭(即执行完毕)时会关闭所有正在运行的子线程(将子线程join到父进程)。但是在以下情况下,进程不必关闭线程:
  
 +  * 线程从父进程上分离。参见`t:​detach()`。请注意线程也可以附着于其他父进程,参见`t:​attach()`。
  
-**Detachable**:​ By default, threads are owned by the process in which they are created (note that threads themselves are a process). The owning process is known as the parent process. When a parent process is closing (i.e. it has reached the end of its execution) it will close(i.e. join) all of its running child threadsA process does not have to close a thread when:+  ​父进程抛出了异常或调用了`os.exit`,此时所有附着在上面的线程都会被杀死。请注意,重启也会杀死所有线程。
  
 +  * 线程被杀死,参见`t:​kill()`。
  
-  * The thread detaches from the parent process. see `t:detach()`. Note that a thread can also attach to another parent. see `t:attach()`+  * 线程被手动暂停,参见`t:suspend()`
  
-  * The parent process throws an exception or calls `os.exit` in which case all attached threads are killed. Note that rebooting also kills all threads.+====独立事件注册====
  
-  ​The thread is killed. see `t:kill()`+每个线程都维护了一套独立的事件注册机制;不继承也不分享。线程中创建的所有事件注册记录(即侦听器或定时器)都只从属于此线程。 
 +  * 线程结束时,其所有事件注册记录都会随之结束。 
 +  ​`suspended`(暂停的)线程会忽略事件(参见`t:status() suspended`) 
 +  * 一个线程不可以访问/​移除/​交互其他线程的事件注册记录。 
 +  * 被推送的事件对系统中的所有运行中线程可见。 
 +  * 两个独立的线程可以对同一个事件`event.pull`,每个线程都会独立观测到此事件。 
 +===== 概述 =====
  
-  * The thread is manually suspended. see `t:​suspend()`+线程主要有两种用途是其他选择无法提供:
  
-====Event Registration Independence====+- 你需要编写一个函数,其中进行了阻塞式调用,但不阻塞程序其它部分的运行。 
 +- 你需要编写长期运行的后台函数,而不想手动管理其yield与resum。
  
-A thread maintains an independent set of event registrations;​ it does not inherit any and it does not share any. Any event registration made (e.g. listeners or timers) inside a thread belongs to that thread. +===== 函数 ​=====
-  * When a thread dies all of its event registrations die with it. +
-  * A `suspended` thread ignores events (see `t:status() suspended`) +
-  * A thread cannot access/​remove/​interfere with another thread'​s event registrations. +
-  * A pushed event is observed by all running threads on the system. +
-  * Two separate threads can `event.pull` for the same event, and each thread will observe the event independently. +
-===== Overview ​=====+
  
-There are two main use cases for using threads over other viable options+此处定义了两类API。
  
-- You want to write a function that makes blocking calls without blocking the rest of your application+1[[api:​thread:​zh#​线程API|线程]]API,或者说静态函数,由`require("​thread"​)`提供。 
-- You want a long running background function without having to manage yielding and resuming it manually.+2[[api:​thread:​zh#​线程句柄API|线程句柄]]API,或者说适用于`thread.create`创建的线程_对象_的api。在此文档中这些线程句柄将会仅以`t`表示。
  
-===== Functions ===== +===== 线程API =====
- +
-There are two sections of API defined here. +
- +
-1. The [[api:​thread#​Thread_API|thread]] api, or the static functions, provided by `require("​thread"​)` +
-2. The [[api:​thread#​Thread_Handle_API|thread handle]] api, or the api available the thread _objects_ created by `thread.create`. In this documentation these thread handles will be denoted by just `t`. +
- +
-===== Thread ​API =====+
  
 - `thread.create(thread_proc:​ function[, ...]): table` - `thread.create(thread_proc:​ function[, ...]): table`
  
-  ​Starts a new thread executing the function ​`thread_proc` ​and returns its thread handle, see [[api:​thread#​Thread_Handle_API|Thread Handle ​API]]. This method takes an optional ​`...` which is passed to `thread_proc`. The runtime of the thread continues autonomously.+  ​开启一个执行函数`thread_proc`的新线程,并返回其线程句柄,参见[[api:​thread:zh#线程句柄API|线程句柄API]]。此方法可接收可选的`...`参数,这些参数将会被传递给`thread_proc`。 线程将自动开始运行。
  
 ```lua ```lua
Line 61: Line 57:
 ``` ```
  
-Output:+输出:
 ``` ```
 Main program start Main program start
Line 71: Line 67:
 - `thread.waitForAll(threads:​ table[, timeout: number]): boolean, string` - `thread.waitForAll(threads:​ table[, timeout: number]): boolean, string`
  
-  ​Waits for the array of `threads` ​to complete. This blocking call can return in `timeout` ​seconds if provided. Returns success and an error message on failure. A thread is "​completed"​ under multiple conditions, see `t:​join()` ​for details.+  ​等待给出的`threads`全部执行完成。此阻塞式操作可以在给出的`timeout`秒超时时间后返回,若给出此值的话。返回值为是否成功,若失败还会返回报错信息。线程可以在多种条件下被认定为”执行完成“,详见`t:join()`
  
 ```lua ```lua
Line 85: Line 81:
 ``` ```
  
-Output:+输出:
 ``` ```
 Main program start Main program start
Line 95: Line 91:
 - `thread.waitForAny(threads:​ table[, timeout: number): boolean, string` - `thread.waitForAny(threads:​ table[, timeout: number): boolean, string`
  
-  ​Waits for any single thread to complete and is otherwise equivalent to `thread.waitForAll()`+  ​等待给出线程中的某一个完成,其他方面`thread.waitForAll()`一致。
  
 ```lua ```lua
Line 115: Line 111:
 ``` ```
  
-Output:+输出:
 ``` ```
 Main program start Main program start
Line 125: Line 121:
 ``` ```
  
-Please note that threads resume order is not specified and this example may print "​D"​ before it prints ​"Main program end"+请注意线程恢复的顺序并未指定,此样例中也有可能在输出"Main program end"之前就输出"​D"​。
  
 - `thread.current():​ table` - `thread.current():​ table`
  
-  ​Returns the current thread ​`t` object. The init process does not represent a thread and nothing is returned from this method if called from the init process and not inside any thread.+  ​返回当前线程对象`t`init进程不代表任何线程,此函数在init进程内而且不在任何线程内调用时不会有返回值。
  
  
  
-===== Thread Handle ​API =====+===== 线程句柄API =====
  
 - `t:​resume():​ boolean, string` - `t:​resume():​ boolean, string`
  
-  ​Resumes (or thaws) a suspended thread. Returns success and an error message on failure. A thread begins its life already in a running state and thus basic thread workflows will not ever need to call `t:​resume()`. A "​running"​ thread will autonomously continue until it completes. ​`t:resume()` is only necessary to resume a thread that has been suspended(`t:suspend()`). **Note** that because you are not directly resuming the thread any exceptions thrown from the thread are absorbed by the threading library and not exposed to your process.+  ​恢复(或者说解冻)一个暂停的线程。返回操作是否成功,若失败额外返回一条报错信息。线程在创建时直接就是运行状态,因此在基本的线程工作流程中完全用不到调用`t:​resume()`。“运行中”的线程会自动继续,直到执行完毕。只有在需要恢复被暂停的(`t:suspend()`)线程时才需要`t:resume()`**请注意,**因为你不是直接恢复线程,线程抛出的一切异常都会被线程运行库吸收,不会暴露给你的进程。
  
-  * At this time there is no way to hook in an exception handler for threads but for now `event.onError` ​is used to print the error message to "/​tmp/​event.log"​. Please note that currently the hard interrupt exception is only thrown once, and the behavior of a process with threads when a hard interrupt is thrown is unspecified. At this time, any one of the threads or the parent process may take the exception. These details are not part of the specification for threads and any part of this implementation detail may change later.+  * 目前还无法为线程挂载异常处理函数,但是现在可以用`event.onError`将报错信息输出到"/​tmp/​event.log"​。请注意目前硬中断异常只会抛出一次,并且在抛出硬中断时,带线程的进程执行的行为仍未指定。目前,任何一个线程或父进程都可能接收到异常。这些细节并不是线程规范的一部分,任何实现细节的部分都可能在以后发生变化。
  
 - `t:​suspend():​ boolean, string` - `t:​suspend():​ boolean, string`
  
-  ​Suspends (or freezes) a running thread. Returns success and an error message on failure. A "​suspended"​ thread never autonomously wakes up and dies as soon as its parent process (if attached) closes. A suspended thread ignores events. That means any event listeners or timers created inside the thread will not respond to event notifications. Note that threads do not buffer event signals and a suspended thread may miss event signals it was waiting for. For example, if a thread was last waiting on `event.pull("​modem_message"​)` ​and is "​suspended"​ and a "​modem_message" ​is received by the computer then the thread will miss the event and never know it happened. Please note that if you suspend a thread that is blocked waiting for an event, it is unspecified which event the thread will receive when it is next resumed.+  ​暂停(或者说冻结)一个运行中的线程。返回操作是否成功,若失败额外返回一条报错信息。“暂停的”线程不会自动唤醒,也不会随其父进程(若附有的话)结束而结束。暂停的线程会忽略出现的事件,代表此线程中定义的任何事件侦听器和定时器都不会响应事件通知。请注意线程不会缓存事件信号,暂停的线程可能会错失其等待的信号。例如,假设一个线程最近一次使用了`event.pull("​modem_message"​)`等待信号,并且被“暂停”了,此时电脑收到了一条"​modem_message"​。这样线程将错失事件,永远不知道发生了什么。请注意如果你暂停了一条正在被阻塞以等待事件的线程,线程下次被唤醒时会接收到什么事件是未指定的。
   ​   ​
-  ​Suspending the current thread causes the thread to immediately ​yield and does not resume until `t:​resume()` ​is called explicitly elsewhere.+  ​暂停当前线程就会导致线程立刻yield,在其他地方显式调用`t:​resume()`之前也不会恢复。
  
-**Special notes about `t:resume``t:​suspend`**+**`t:​resume``t:suspend`的特别注释**
  
-Do not think of these methods as `coroutine.resume()` ​nor `coroutine.yield()`. These methods are indirect and a thread will asynchronously start or stop running on its own. Contrast this to coroutine methods which directly and immediately invoke execution or leave execution of a coroutine. Consider these examples:+不要把这两个方法当作`coroutine.resume()``coroutine.yield()`。这两个方法是间接的,而且线程是独自异步开始或停止运行的。请将这一特性与协程方法相对比,协程方法是直接的,而且会立即唤起或离开协程的执行。参考这些样例:
  
 ```lua ```lua
 local thread = require("​thread"​) local thread = require("​thread"​)
-local t -- this example needs an upvalue to t+local t -- 此样例需要t的upvalue
 t = thread.create(function() t = thread.create(function()
   print("​start"​)   print("​start"​)
Line 163: Line 159:
 ``` ```
  
-Output:+输出:
 ``` ```
 start start
Line 183: Line 179:
 ``` ```
  
-Output:+输出:
 ``` ```
 start start
Line 194: Line 190:
 - `t:kill()` - `t:kill()`
  
-  ​Stabby stab! Kills the thread dead. The thread is terminated and will not continue its thread function. Any event registrations it made will die with it. Keep in mind that the core underlying ​Lua type is a coroutine which is not a preemptive thread. Thus, the thread'​s stopping points are deterministic,​ meaning that you can predict exactly where the thread will stop. Consider this example:  +  ​给它一刀!将线程杀死。线程将会被终止,不能再继续执行其线程函数。它的所有事件注册记录也都会随之结束。请注意核心底层实际上是Lua协程,协程不是抢占式线程。因此线程的结束点是可知的,意味着你可以预测线程结束的准确位置。参考此样例:
  
 ```lua ```lua
Line 213: Line 208:
 ``` ```
  
-Output:+输出:
 ``` ```
 running running
Line 223: Line 218:
 - `t:​status():​ string` - `t:​status():​ string`
  
-  ​Returns the thread status as a string.+  ​以字符串形式返回线程状态。
  
-  * **"​running"​**+  * **"​running" ​运行**
  
-  ​A running thread will continue (autonomously reactivating) after yields and blocking calls until its thread function exits. This is the default and initial state of a created thread. A thread remains in the "​running"​ state even when blocked or not active. A running thread can be suspended(`t:​suspend()`) or killed (`t:kill()`) but not resumed(`t:​resume()`). A running thread will block calls to `t:​join()` ​and block its parent from closing. Unlike a coroutine which appears "​suspended"​ when not executing in this very moment, a thread state remains "​running"​ even when waiting for an event.+  ​运行中的线程会在yield和阻塞式调用后继续运行(自动重新开始活动),直到其线程函数退出。这是创建后线程的初始与默认状态。线程就算在阻塞或不活动的状态下也会保持“运行”状态。运行中的线程可以被暂停(`t:​suspend()`)或杀死(`t:kill()`),但是不可以恢复(`t:​resume()`)。运行中的线程将会阻塞`t:join()`的调用,也会阻塞其父进程的关闭。与协程不同,协程在未执行时即为“暂停”状态,而线程就算在等待事件时也是“运行”状态。
  
-  * **"​suspended"​**+  * **"​suspended" ​暂停**
  
-  ​A suspended thread will remain suspended and never self resume execution of its thread function. A suspended thread is automatically killed when its attached parent closes or when you attempt to `t:​join()` ​it. A suspended thread ignores event signals, and any event registrations made from the context of the thread, or any child threads created therein, also ignore any event signals. A suspended thread'​s children behave as if suspended even if their status is "​running"​. A suspended thread can be resumed(`t:​resume()`) or killed (`t:kill()`) but not suspended(`t:​suspend()`).+  ​被暂停的线程会保持暂停状态,永远不会自动恢复执行其线程函数。暂停的线程会在其附着的父进程关闭时或你试图`t:join()`它时自动被杀死。暂停的线程会忽略事件信号,此线程的上下文所创建的,或其创建的任何子线程所创建的事件注册记录,也都会忽略事件信号。暂停线程的子线程表现会与暂停一样,即使其状态为“运行”。暂停的线程可以恢复(`t:​resume()`)或者杀死(`t:kill()`),但不可以暂停(`t:​suspend()`)。
  
-  * **"​dead"​**+  * **"​dead" ​死亡**
  
-  ​A dead thread has completed or aborted its execution or has been terminated. It cannot be resumed(`t:​resume()`) nor suspended(`t:​suspend()`). A dead thread does not block a parent process from closing. Killing a dead thread is not an error but does nothing.+  ​死亡的线程是结束了或放弃了自己的运行或被终止的线程。它不可被恢复(`t:​resume()`)也不可被暂停(`t:​suspend()`)。死亡的线程不会阻塞父进程的关闭。杀死死亡的线程不会报错,而是什么也不做。
  
-** Status Examples ​**+** 状态样例 ​**
  
 ```lua ```lua
Line 249: Line 244:
 ``` ```
  
-Output:+输出:
 ``` ```
 before sleep before sleep
Line 272: Line 267:
 ``` ```
  
-Output:+输出:
 ``` ```
 before sleep before sleep
Line 283: Line 278:
 - `t:​attach([level:​ number]): boolean, string` - `t:​attach([level:​ number]): boolean, string`
  
-  ​Attaches a thread to a process, conventionally known as a child thread or attached thread. ​`level` ​is an optional used to get parent processes, ​or nil uses the currently running process. When initially created a thread is already attached to the current process. This method returns nil and an error message if `level` ​refers to a nonexistent process, otherwise it returns truthy. An attached thread blocks its parent process from closing until the thread dies (or is killed, or the parent process aborts). +  ​将一个线程附着到一个进程,通常称为子线程或附着线程。`level`为可选参数,可用于获取父进程,传递0或`nil`则使用当前运行进程。在最初创建线程时,线程已经被附着于当前进程。若`level`指向了不存在的线程,则此方法会返回`nil`与一条报错信息,否则返回true。附着的线程将会阻塞其父进程的关闭,直到线程死亡(或者被杀死,或者父进程放弃执行)。 
 +  
 - `t:​detach():​ table, string` - `t:​detach():​ table, string`
  
-  ​Detaches a thread from its parent if it has one. Returns ​nil and an error message if no action was taken, otherwise returns self (handy if you want to create and detach a thread in one line). A detached thread will continue to run until the computer is shutdown or rebooted, or the thread dies.+  ​将一个线程从其父进程(若有)上解除附着。若未执行动作则返回`nil`与一条报错信息,否则返回自身(以便于你想在同一行中创建一个线程并将其解除附着)。解除附着的线程会继续执行,直到电脑关机或重启,或者线程死亡。
  
 ```lua ```lua
Line 295: Line 290:
 - `t:​join([timeout:​ number]): boolean, string` - `t:​join([timeout:​ number]): boolean, string`
  
-  ​Blocks the caller until `t` is no longer running or (optionally) returns false if `timeout` ​seconds is reached. After a call to `t:​join()` ​the thread state is "​dead"​. Any of the following circumstances allow `join` ​to finish and unblock the caller+  ​阻塞调用者,直到`t`不再运行。或者在到达了`timeout`秒的超时时间后返回`false`(可选)。在`t:join()`的调用结束后线程的状态将为“死亡”。任一下列情况都会导致`join`结束并停止阻塞调用者:
  
-  * The thread continues running until it returns from its thread function +  * 线程继续运行,直到其从线程函数中返回。 
-  * The thread aborts, or throws an uncaught exception +  * 线程被放弃,或抛出了未被捕获的异常。 
-  * The thread is suspended +  * 线程被暂停。 
-  * The thread is killed+  * 线程被杀死
  
-  ​Calling ​`thread.waitForAll({t})` ​is functionally equivalent to calling ​`t:join()`. When a processs is closing it will call `thread.waitForAll` ​on the group of its child threads if it has any. A child thread blocks its parent thread by the same machanism.+  ​调用`thread.waitForAll({t})`在功能上与调用`t:join()`一致。在进程结束时会对其子线程调用`thread.waitForAll`(若有)。子线程也通过同样的机制阻塞其父进程。
  
-===== Thread Exception Example ​=====+===== 线程异常样例 ​=====
  
-This example demonstrates what happens when a thread throws an exception. A thread stops executing and becomes "​dead"​ when it throws an uncaught exception. The exception message is not printed to stdout ​nor stderr ​(see `t:​resume()`) for details. ​+此样例演示了线程抛出异常时会发生什么。线程在抛出未捕获的异常时会停止执行并进入“死亡”状态。报错信息将不会输出到stdoutstderr(详见`t:​resume()`)。 ​
  
 ```lua ```lua
Line 315: Line 310:
 local reader = thread.create(function() local reader = thread.create(function()
   print("​reader start"​)   print("​reader start"​)
-  error("​thread abort"​) -- throws an exception+  error("​thread abort"​) -- 抛出一个异常
   print("​reader done")   print("​reader done")
 end) end)
Line 321: Line 316:
 ``` ```
  
-Output+输出:
 ``` ```
 p start p start
Line 328: Line 323:
 ``` ```
  
-===== Thread Interrupt Handler Example ​=====+===== 线程中断处理函数样例 ​=====
  
-This example demonstrates how you would register a function that handles soft interrupts (^c) to close file handles, release resources, etc, and then exit the whole program.+此样例演示了你该如何注册处理软中断(^c)的函数,用于关闭文件句柄、释放资源等等,然后退出整个程序。
  
 ```lua ```lua
Line 350: Line 345:
  
 thread.waitForAny({cleanup_thread,​ main_thread}) thread.waitForAny({cleanup_thread,​ main_thread})
-os.exit(0) -- closes all remaining threads+os.exit(0) -- 关闭所有剩余线程
 ``` ```
  
-Assuming the user presses ​^c to send an interrupt +假设用户按下了^c发送了一次软中断 
-Output+ 
 +输出:
 ``` ```
 main program main program
Line 361: Line 357:
 ``` ```
  
-===== Thread ​Yield/​Pull ​Without Blocking Example ​=====+===== 非阻塞式线程Yield/Pull操作样例 ​=====
  
-This example demonstrates that now OpenOS ​supports non blocking threads.+此样例演示了现在OpenOS可支持非阻塞式线程。
  
 ```lua ```lua
Line 379: Line 375:
 ``` ```
  
-Output+输出:
 ``` ```
 custom_event_a custom_event_a