在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 ++)编写。
答案 0 :(得分:1)
我现在已经对此进行了一些调查,我找到了解决实际问题的方法,但不是我想要的方法。
我原本以为我能够找到并清理任何不需要的打开文件,但事实证明这很难。我找到了一些不同的教程(here和here)如何执行此操作,但它们依赖于未记录的 API。我无法使这项技术发挥作用 - 可能是我做错了,或者可能在Windows Server 2012中更改了API - 但无论如何我不确定我是否想去那里; Sysinternals可以跟踪这些内容并保持Process Explorer正常工作,但我不希望我的项目有这样的维护负担。
我现在有两个选择:
在父(调用)进程中放入一些特殊的大小写代码,让它在适当的时候调用CreateProcess
并禁用继承(它当前使用_spawnlp
,因为它与Unix风格兼容管道和文件句柄,你不能非常可靠地使用CreateProcess
。
让进程立即使用CreateProcess
调用自身,然后退出(或无限期等待)以杀死任何不需要的句柄。
第一种感觉更有效率。第二种是更灵活(它允许流程自己选择)。
我想我会选择第一选项,因为对于我目前的需求,感觉就像是最差的。
答案 1 :(得分:-1)
首先是一些反向信息 - 为什么循环在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混合了不同类型的句柄(文件句柄,内存句柄,进程句柄......)。如果你能获得所有句柄的列表,你将不得不区别对待。
另一点是Windows库在内部使用一些句柄。如果您只是关闭父进程继承的所有句柄,您将冒着程序崩溃的风险,因为Windows库可能依赖于其中一些句柄。
因此,必须确保父应用程序确保没有句柄保持打开状态。默认情况下,Windows中不会继承句柄。但是,C库包装器(例如“fopen()”)将设置“继承句柄”标志,以便继承句柄。