fs.read 在自定义信号处理程序中阻止 process.exit

Posted

技术标签:

【中文标题】fs.read 在自定义信号处理程序中阻止 process.exit【英文标题】:fs.read prevents process.exit in custom signal handler 【发布时间】:2016-04-05 14:33:37 【问题描述】:

我无法在信号处理程序中使用process.exit() 让我的nodejs 应用程序退出。这是因为我在 Linux 输入事件节点 (/dev/input/mouse1) 上有一个挂起的读取操作。我花了几个小时研究,但我只能找到this SO question。我尝试使用fs.ReadStream 就像在那里使用的那样并调用它的destroy 方法,但它也没有工作。即使通过阅读 nodejs 源代码,我也无法想出一个主意。然后是这个issue on github,有点相关。

到目前为止,我想出了一些技巧来解决这个问题,但没有什么干净的:

    使用比process.exit更强的东西,也许process.abort 生成一个子进程 (childProcess.fork) 到 read,我可以从父进程终止它。但这会创建一个新的 nodejs 实例,内存使用量约为 10mb。 用我可以更好地控制正在发生的事情(使用线程等)的语言 (C++) 编写程序并从 javascript 调用它。虽然我更喜欢留在 js-land。 或者也许有人知道可以帮助我以不同方式实现目标的工具? (请参阅下面的背景信息)。也许我不必使用/dev/input/

基本上,我需要一种直接或间接取消挂起的read 操作的方法(例如,通过从active_handles 列表中清除它们)。 提前感谢您的回答!

示例

在下面的代码示例中,我可以按ctrl+c,但nodejs只有在我移动鼠标后才会退出:

'use strict'
const fs = require('fs');

const buf = new Buffer(24);
const mouse = fs.openSync('/dev/input/mouse1', 'r');
const onRead = (err, bytesRead, buffer) => 
    console.log('read');
    if (!err) 
        process.nextTick(fs.read, mouse, buf, 0, buf.length, null, onRead);
    
;
fs.read(mouse, buf, 0, buf.length, null, onRead);

process.on('SIGINT', () => 
    fs.closeSync(mouse);
    process.exit();
);

背景资料

我正在开发一个基于运行 nodejs 脚本的树莓派的小项目。我希望程序通过 USB 鼠标的滚轮和 GPIO 附加按钮来响应用户输入。因此,我将onoff 库用于GPIO 的东西。 onoff 文档建议安装自定义 SIGINT 处理程序以在程序退出之前释放资源,这就是这种愿望的来源。为了在没有窗口系统甚至终端的情况下处理滚轮数据,我最终想让this library工作,但现在我遇到了上述问题。

【问题讨论】:

您是否检查过信号处理程序是否被实际调用?您使用fs.openSyncfs.read 而不是fs.createReadStream 并添加read 事件处理程序的任何具体原因? pstop中的进程在尝试中断时处于什么状态? @jcaron 感谢您的回复。这段代码只是一个简单的例子。我在问题中提到我已经使用 ReadStream 测试了替代实现。此外,fs.ReadStream 只是 fs.read 的某种包装,请参阅here。处理程序被调用,您甚至可以从中console.log。能否详细说明如何在top/ps中查找进程状态? 我今天也偶然发现了这个。一种解决方案是使用诸如 node-hid 之类的库,它使用 hidapi,并在内部进行了足够的清理,但我想避免添加另一个需要编译的库。感谢您提供解决方法列表。最后,您是否设法为此找到了另一种解决方案? @AndreT 这是 5 年前的事了:D 但 IIRC 这是一门我最终完全放弃的单门课程。所以恐怕没有解决办法。我遵循的最后一种方法是将我自己的事件输入设备,以便 nodejs 的 io lib 中的阻塞线程将恢复并允许我正确关闭。不确定我是否可以正常工作... 【参考方案1】:

可能有点粗略,但以下内容呢:

process.on('SIGINT', () => 
    fs.closeSync(mouse);
    setTimeout(process.exit, 1000);
);

【讨论】:

您好,感谢您的回答。它能为您提供帮助吗?我在发布这个问题之前尝试过,但它对我不起作用。

以上是关于fs.read 在自定义信号处理程序中阻止 process.exit的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 Facebook 上创建自定义信使机器人?

在线程中选择()系统调用?

信号的处理方式sigaction函数

LINUX系统编程之IPC

进程信号的本质与处理

使用sigaction来取代signal作为信号处理器函数