0

在 Windows (MinGW) 中,我的程序从调用进程继承了不需要的句柄。

该过程不需要打开这些文件,但是因为它存在于父级的生命周期之外,所以我遇到了文件保持打开状态的常见问题。

在 Linux 上,我解决了这样的问题:

// Close all file descriptors
// It's hard to figure out how many are open, but the first 1000 should do
int fd;
for (fd = 0; fd < 1000; fd++)
  close (fd);

这似乎不适用于 Windows。

如何确定哪些文件句柄已被继承?我怎样才能关闭它们?

该项目使用 MinGW 和 Windows 的 Unix 兼容性 API 用 C(非 C++)编写。

4

2 回答 2

1

我现在对此进行了一些调查,并且找到了解决实际问题的方法,但不是我想要的。

我曾以为我能够找到并清理任何不受欢迎的打开文件,但事实证明这很难。我找到了一些不同的教程(这里这里)如何做到这一点,但它们依赖于未记录的API。我无法使这项技术发挥作用——可能是我做错了,或者可能是 Windows Server 2012 中的 API 发生了变化——但无论如何我都不确定我是否想去那里;Sysinternals 可以跟踪这些东西并保持 Process Explorer 正常工作,但我不希望我的项目有这种维护负担。

我现在有两个选择:

  1. 在父(调用)进程中放置一些特殊情况代码,以便CreateProcess在适当的时候禁用继承调用(它当前使用_spawnlp是因为它与 Unix 风格的管道和文件句柄兼容,并且您不能CreateProcess非常可靠地使用它们) .

  2. 让进程立即调用自身,CreateProcess然后退出(或无限期等待)以杀死任何不需要的句柄。

第一个感觉更有效率。第二个更灵活(它允许进程自己选择)。

我想我会选择选项一,因为就我目前的需求而言,这感觉是最糟糕的。

于 2013-09-16T11:41:12.150 回答
0

首先是一些背景信息 - 为什么循环在 Windows 下不起作用:

在 Linux 中,句柄的数字是 0...n。传递给“close()”的句柄和类似函数直接传递给操作系统:

void close(int handle)
{
    syscall(SYS_CLOSE,handle);
}

然而,在 Windows 中,操作系统使用自己的句柄,类似于指针地址,而 C 库使用某种转换表:

void close(int handle)
{
    CloseHandle(table[handle]);
    table[handle]=NULL;
}

如果句柄保持打开,C 库不知道(不是 STDIN、STDOUT、STDERR)这些句柄将不在表中。

现在关于实际问题:

与 Linux 不同,Windows 混合了不同类型的句柄(文件句柄、内存句柄、进程句柄……)。如果您可以获得所有句柄的列表,则必须以不同的方式对待 dem。

另一点是 Windows 库在内部使用了一些句柄。如果您简单地关闭父进程继承的所有句柄,您将面临程序崩溃的风险,因为 Windows 库可能依赖于其中一些句柄。

因此,绝对由父应用程序确保没有句柄保持打开状态。默认情况下,句柄不会在 Windows 中继承。然而,C 库包装器(例如“fopen()”)将设置“继承句柄”标志,以便继承句柄。

于 2013-09-13T13:41:17.660 回答