在https://z0ltan.wordpress.com/2016/09/02/basic-concurrency-and-parallelism-in-common-lisp-part-3-concurrency-using-bordeaux-and-sbcl-threads/的Timmy Jose的博客文章中,他给出了一个错误的示例,该错误的方法从线程内部打印到顶层(以Bordeaux Threads为例,尽管我使用的是Lparallel): / p>
(defun print-message-top-level-wrong ()
(bt:make-thread
(lambda ()
(format *standard-output* "Hello from thread!")))
nil)
(print-message-top-level-wrong) -> NIL
解释是:“如果我们没有在单独的线程中运行相同的代码,它将运行良好。发生的情况是每个线程都有其自己的堆栈,变量会反弹。在这种情况下,即使对于{{ 1}},这是一个全局变量,我们认为应该对所有线程可用,它在每个线程内反弹!”
如果该函数在Allegro CL中运行,这正是发生的情况。但是,在SBCL中,该功能确实会在终端上打印预期的输出。这是否意味着*standard-output*
在SBCL中没有反弹?通常,是否有跨平台的方法可以从线程内部打印到*standard-output*
?
在多线程情况下,通常应协调到终端的打印,以避免可能同时从多个流中进行打印。但是似乎没有可用的功能*standard-output*
或atomic-format
。当有多个线程时,是否有一种简单的方法来避免打印干扰(假设锁/互斥锁对于每个单独的打印操作来说都太昂贵了?)?
答案 0 :(得分:2)
如果实际上有一个 global 绑定(在全局环境中是一个绑定),它确实适用于所有线程;请参阅documentation for bt:make-thread。只有动态(重新)绑定是线程本地的。不同的实现方式/绑定它们的方式。有时实际上对用户程序有效的绑定是全局的,有时不是全局的。
我喜欢在需要时使用某种队列或通道来协调输出;我还没有遇到过锁定开销过高的情况。
也许您可以尝试使用乐观锁定进行操作,但是我不知道针对库进行了哪些操作(某些Lisp实现确实具有可以使用的CAS操作)。这应该与所使用的并行性库正交。
EDIT :只能在SBCL手册中找到:sb-concurrency具有无锁队列和邮箱。