1 Star 0 Fork 3

rookieagle/Elisp

forked from advanceflow/Elisp 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
38-线程.org 10.62 KB
一键复制 编辑 原始数据 按行查看 历史
advanceflow 提交于 2022-05-28 10:12 . finish s2

38 线程

Emacs Lisp 提供了一种有限形式的并发,称为线程。 给定 Emacs 实例中的所有线程共享相同的内存。 Emacs Lisp 中的并发是“主要是协作的”,这意味着 Emacs 只会在明确定义的时间在线程之间切换执行。 然而,Emacs 线程支持被设计成以后允许更细粒度的并发,正确的程序不应该依赖协作线程。

目前,线程切换将在通过 thread-yield 进行显式请求时发生,在等待键盘输入或异步进程的进程输出时(例如,在接受进程输出期间),或者在与线程相关的阻塞操作期间,例如互斥锁或线程连接。

Emacs Lisp 提供了创建和控制线程,以及创建和控制互斥锁和条件变量的原语,这对于线程同步很有用。

虽然全局变量在所有 Emacs Lisp 线程之间共享,但局部变量不是——动态的 let 绑定是本地的。 每个线程也有自己的当前缓冲区(请参阅当前缓冲区)和自己的匹配数据(请参阅匹配数据)。

请注意,Emacs Lisp 实现对 let 绑定进行了特殊处理。 除了使用 let 之外,没有其他方法可以复制这种展开和倒带行为。 例如,使用 unwind-protect 编写的 let 的手动实现不能将变量值安排为线程特定的。

在词法绑定的情况下(请参阅变量绑定的范围规则),闭包是与 Emacs Lisp 中的任何其他对象一样的对象,并且闭包中的绑定由调用闭包的任何线程共享。

38.1 基本线程函数

可以创建和等待线程。 一个线程不能直接退出,但是可以隐式退出当前线程,并且可以给其他线程发信号。

Function: make-thread function &optional name ¶

创建一个调用函数的新执行线程。 当函数返回时,线程退出。

创建新线程时没有有效的局部变量绑定。 新线程的当前缓冲区继承自当前线程。

可以提供 name 来为线程命名。 该名称仅用于调试和信息目的; 它对 Emacs 没有任何意义。 如果提供了名称,则它必须是字符串。

此函数返回新线程。

Function: threadp object ¶

如果 object 表示 Emacs 线程,则此函数返回 t,否则返回 nil。

Function: thread-join thread ¶

阻塞直到线程退出,或者直到当前线程发出信号。 它返回线程函数的结果。 如果线程已经退出,则立即返回。

Function: thread-signal thread error-symbol data ¶

与信号类似(参见如何发出错误信号),但信号是在线程线程中传递的。 如果线程是当前线程,那么这只是立即调用信号。 否则,线程将在信号变为当前时立即接收信号。 如果线程被互斥锁、条件等待或线程连接调用阻塞; 线程信号将解锁它。

如果线程是主线程,则信号不会在那里传播。 相反,它在主线程中显示为消息。

Function: thread-yield ¶

让执行到下一个可运行线程。

Function: thread-name thread ¶

返回线程的名称,指定给 make-thread。

Function: thread-live-p thread ¶

如果线程处于活动状态,则返回 t,否则返回 nil。 只要它的函数仍在执行,线程就处于活动状态。

Function: thread--blocker thread ¶

返回线程正在等待的对象。 此函数主要用于调试,并被赋予“双连字符”名称以表明这一点。

如果线程在线程连接中被阻塞,则返回它正在等待的线程。

如果线程在互斥锁中被阻塞,则返回互斥锁。

如果线程在条件等待中被阻塞,则返回条件变量。

否则,这将返回 nil。

Function: current-thread ¶

返回当前线程。

Function: all-threads ¶

返回所有活动线程对象的列表。 每次调用都会返回一个新列表。

Variable: main-thread ¶

此变量保持 Emacs 正在运行的主线程,如果 Emacs 在没有线程支持的情况下编译,则为 nil。

当线程运行的代码发出未处理的错误信号时,线程退出。 其他线程可以使用以下函数访问导致线程退出的错误表单。

Function: thread-last-error &optional cleanup ¶

此函数返回线程因错误退出时记录的最后一个错误形式。 每个异常退出的线程都会用一个新值覆盖前一个线程错误存储的表单,因此只能访问最后一个。 如果 cleanup 不为零,则存储的表单将重置为 nil。

38.2 互斥体

互斥锁是排他锁。 在任何时候,零个或一个线程可能拥有一个互斥锁。 如果一个线程试图获取一个互斥锁,并且该互斥锁已经被某个其他线程拥有,那么获取线程将阻塞,直到该互斥锁可用。

Emacs Lisp 互斥体是一种称为递归的类型,这意味着线程可以重新获取它拥有的互斥体任意次数。 互斥锁会记录它被获取的次数,并且每次获取互斥锁都必须与释放配对。 互斥锁线程的最后一次释放会将其恢复为无主状态,从而可能允许另一个线程获取互斥锁。

Function: mutexp object ¶

如果 object 表示 Emacs 互斥体,则此函数返回 t,否则返回 nil。

Function: make-mutex &optional name ¶

创建一个新的互斥体并返回它。 如果指定了名称,则它是给互斥体的名称。 它必须是一个字符串。 该名称仅用于调试目的; 它对 Emacs 没有任何意义。

Function: mutex-name mutex ¶

返回互斥锁的名称,指定给 make-mutex。

Function: mutex-lock mutex ¶

这将阻塞,直到该线程获得互斥体,或者直到该线程使用线程信号发出信号。 如果 mutex 已由该线程拥有,则返回。

Function: mutex-unlock mutex ¶

释放互斥锁。 如果互斥锁不属于该线程,这将发出错误信号。

Macro: with-mutex mutex body… ¶

这个宏是在持有互斥锁时评估表单的最简单和最安全的方法。 它获取互斥体,调用主体,然后释放互斥体。 它返回正文的结果。

38.3 条件变量

条件变量是线程阻塞直到某个事件发生的一种方式。 一个线程可以等待一个条件变量,当其他线程通知该条件时被唤醒。

条件变量与互斥体相关联,并且在概念上与某些条件相关联。 为了正确操作,必须获取互斥体,然后必须循环等待线程,测试条件并等待条件变量。 例如:

(with-mutex mutex
  (while (not global-variable)
    (condition-wait cond-var)))

互斥体确保原子性,循环是为了健壮性——可能存在虚假通知。

同样,在通知条件之前必须持有互斥锁。 典型且最佳的方法是获取互斥锁,进行与此条件相关的更改,然后通知它:

(with-mutex mutex
  (setq global-variable (some-computation))
  (condition-notify cond-var))
Function: make-condition-variable mutex &optional name ¶

创建一个与互斥锁关联的新条件变量。 如果指定了名称,则它是赋予条件变量的名称。 它必须是一个字符串。 该名称仅用于调试目的; 它对 Emacs 没有任何意义。

Function: condition-variable-p object ¶

如果 object 表示条件变量,此函数返回 t,否则返回 nil。

Function: condition-wait cond ¶

等待另一个线程通知条件变量 cond。 此函数将阻塞,直到通知条件,或者直到使用线程信号将信号传递给该线程。

调用条件等待而不持有条件的关联互斥体是错误的。

条件等待在等待时释放关联的互斥锁。 这允许其他线程获取互斥锁以通知条件。

Function: condition-notify cond &optional all ¶

通知条件。 在调用它之前,必须持有带有 cond 的互斥锁。 通常条件通知会唤醒单个等待线程; 但如果 all 不为零,则通知所有等待 cond 的线程。

条件通知在等待时释放关联的互斥锁。 这允许其他线程获取互斥锁以等待条件。

Function: condition-name cond ¶

返回传递给 make-condition-variable 的 cond 的名称。

Function: condition-mutex cond ¶

返回与 cond 关联的互斥锁。 请注意,无法更改关联的互斥锁。

38.4 线程列表

list-threads 命令列出所有当前活动的线程。 在结果缓冲区中,每个线程要么通过传递给 make-thread 的名称(参见基本线程函数)来标识,要么通过其唯一的内部标识符(如果它不是用名称创建的话)来标识。 显示创建或上次更新缓冲区时每个线程的状态,以及线程当时被阻塞的对象(如果它被阻塞)。

Variable: thread-list-refresh-seconds ¶

Threads 缓冲区将每秒自动更新两次。 您可以通过自定义此变量来加快或减慢刷新率。

以下是线程列表缓冲区中可用的命令:

b

在该点显示线程的回溯。 这将显示在您按下 b 时线程在其代码中的哪个位置产生或被阻塞。 请注意,回溯是快照; 线程可能同时恢复执行,并处于不同的状态,或者可能已经退出。

您可以在线程的回溯缓冲区中使用 g 来获取更新的回溯,因为回溯缓冲区不会自动更新。 请参阅 Backtraces,了解对回溯和其他对其起作用的命令的描述。

s

信号点的线程。 在 s 之后,键入 q 以发送退出信号或键入 e 以发送错误信号。 线程可以实现对信号的处理,但默认行为是退出任何信号。 因此,仅当您了解如何重新启动目标线程时才应该使用此命令,因为如果必要的线程被杀死,您的 Emacs 会话可能会表现不正确。

g

更新线程列表及其状态。

马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/rookieagle/elisp.git
git@gitee.com:rookieagle/elisp.git
rookieagle
elisp
Elisp
main

搜索帮助