Печать на терминал из (параллельных) потоков (Common Lisp) - PullRequest
1 голос
/ 25 марта 2019

В одном из сообщений в блоге Тимми Хосе на https://z0ltan.wordpress.com/2016/09/02/basic-concurrency-and-parallelism-in-common-lisp-part-3-concurrency-using-bordeaux-and-sbcl-threads/ он приводит пример неправильного способа печати на верхнем уровне из потока (используя в качестве примера нити Бордо, хотя я использую Lparallel):

(defun print-message-top-level-wrong ()
  (bt:make-thread
    (lambda ()
      (format *standard-output* "Hello from thread!")))
  nil)

(print-message-top-level-wrong) -> NIL

Объяснение состоит в том, что «тот же код работал бы нормально, если бы мы не запускали его в отдельном потоке. В результате каждый поток имеет свой собственный стек, в котором переменные возвращаются.случай, даже для *standard-output*, который является глобальной переменной, которая, как мы предполагаем, должна быть доступна всем потокам, восстанавливается внутри каждого потока! "

И это именно то, что происходит, если функция запускается в AllegroCL.Тем не менее, в SBCL функция печатает предполагаемый вывод на терминале.Означает ли это, что *standard-output* не восстанавливается в SBCL?В общем, существует ли кроссплатформенный способ печати в *standard-output* из потока?

В многопоточной ситуации печать на терминале обычно должна координироваться, чтобы избежать потенциальной печати из нескольких потоков одновременно,Но, похоже, нет таких функций, как atomic-format или atomic-print.Существует ли простой способ избежать помех печати при наличии нескольких нитей (при условии, что блокировки / взаимные блокировки слишком дороги для использования в каждой отдельной операции печати)?

1 Ответ

2 голосов
/ 25 марта 2019

Если у вас действительно есть глобальная привязка (привязка в глобальной среде), работает для всех потоков;см. документацию для bt: make-thread .Только динамические (пере) привязки являются локальными для потока.Реализации отличаются тем, как / когда они связывают эти потоки;иногда привязка, которая фактически действует для пользовательских программ, является глобальной, иногда нет.

Мне нравится использовать какую-то очередь или канал для координации вывода в случае необходимости;Я еще не сталкивался с ситуациями, когда накладные расходы на блокировку были непомерно высокими.

Возможно, вы могли бы попробовать что-то с оптимистической блокировкой, но я не знаю, что было сделано для этой библиотеки (некоторые реализации Lisp действительно имеют операции CASчто можно было бы использовать).Это должно быть ортогонально используемой библиотеке параллелизма.

EDIT : Только что найдено в руководстве SBCL: sb-concurrency имеет очереди без блокировки и почтовые ящики.

...