我正在Emacs Lisp中编写一些代码,我希望使用start-process
或类似函数启动子进程。但是,当父emacs进程退出时,我不希望子进程退出。但是,退出父emacs进程似乎总是会杀死所有子进程。以下代码段演示了这一点:
(require 'async)
(async-sandbox
(lambda ()
(require 'package)
(package-initialize)
(require 'async)
(shell-command "{ echo -n 'SPAWNING: '; date; } > ~/temp/ASYNC_LOG")
(start-process-shell-command "subproc" nil
"{ echo -n 'STARTED: '; date; } >> ~/temp/ASYNC_LOG;
sleep 5;
{ echo -n 'FINISHED: '; date; } >> ~/temp/ASYNC_LOG;")
(shell-command "{ echo -n 'SPAWNED: '; date; } >> ~/temp/ASYNC_LOG")
(shell-command "sleep 2")
(shell-command "{ echo -n 'FINISHED WAITING: '; date; } >> ~/temp/ASYNC_LOG")
))
此代码同步生成一个emacs进程(async-sandbox (lambda () ...)
,以便我们可以退出该进程以触发问题。然后,该进程异步生成子进程(start-process-shell-command ...)
。父进程休眠2秒,而子进程休眠5,因此父进程将首先退出。当我运行此代码时,我从未在日志文件中看到“FINISHED”行,表示子进程在2秒后被终止。如果我将父级更改为等待7秒,那么我会在输出中看到FINISHED行。
那么有没有类似的方法来启动子进程,以便在父进程退出时不会被终止?
答案 0 :(得分:1)
以下是我从dired开始的方式:
(require 'dired-aux)
(setq dired-guess-shell-alist-user
'(("\\.pdf\\'" "evince")
("\\.eps\\'" "evince")
("\\.jpe?g\\'" "eog")
("\\.png\\'" "eog")
("\\.gif\\'" "eog")
("\\.tex\\'" "pdflatex" "latex")
("\\.\\(?:mp4\\|mkv\\|avi\\|flv\\)\\'" "vlc")))
(defvar dired-filelist-cmd
'(("vlc" "-L")))
(defun dired-start-process (cmd &optional file-list)
(interactive
(let ((files (dired-get-marked-files t current-prefix-arg)))
(list
(dired-read-shell-command "& on %s: " current-prefix-arg files)
files)))
(apply
#'start-process
(list cmd nil shell-file-name shell-command-switch
(format "nohup 1>/dev/null 2>/dev/null %s \"%s\""
(if (> (length file-list) 1)
(format "%s %s"
cmd
(cadr (assoc cmd dired-filelist-cmd)))
cmd)
(mapconcat #'expand-file-name file-list "\" \"")))))
答案 1 :(得分:0)
Emacs在终止时所做的是向其生成的进程发送信号(我假设它们是process-list
中存在的信号)。这种行为在Emacs C代码中是硬编码的(您可以尝试破解进程列表,删除您想要比Emacs更长的进程,但我不确定它的副作用;可能它们会很难看)
您可以轻松找到Emacs发送的信号(只需为您的某个进程编写信号处理程序)。我猜它是SIGHUP,因此进程知道与用户(Emacs)的连接已丢失。
您可以做的是通过为该信号添加处理程序,使您的进程以不会死的方式处理SIGHUP。如果您对该过程代码没有控制权,您可以用“nohup”包装它(这是@ abo-abo基本上正在做的事情;请参阅abo-abo其他答案以获取实现细节)