GetAttributes在子线程中使用错误的工作目录

时间:2014-03-19 13:12:56

标签: multithreading winapi strawberry-perl chdir file-attributes

我使用File::Find遍历目录树和Win32::File的{​​{1}}函数来查看其中找到的文件的属性。这适用于单线程程序。

然后我将目录遍历移动到一个单独的线程中,它停止工作。 GetAttributesGetAttributes中出现错误消息“{系统无法找到指定的文件”的每个文件都失败。

我将问题追溯到$^E使用File::Find的事实,显然chdir不使用当前目录。我可以通过传递一个绝对路径来解决这个问题,但是后来我可能会遇到路径长度限制,并且在这个脚本运行的地方肯定会出现长路径,所以我真的需要利用GetAttributes和相对路径。

为了演示这个问题,这里有一个脚本,它在当前目录中创建一个文件,在子目录中创建另一个文件,在子目录中创建chdir,并以3种方式查找文件:chdir,{{1} }和system("dir")

当脚本在没有参数的情况下运行时,open显示子目录,GetAttributes在子目录中找到该文件,dir成功返回其属性。使用open运行时,所有测试都在子线程中完成,GetAttributes--thread仍然有效,但dir失败。然后它调用原始目录中的文件open(我们有chdir'ed),然后找到一个!不知怎的GetAttributes正在使用进程的原始工作目录 - 或者可能是主线程的工作目录 - 与所有其他文件操作不同。

我该如何解决这个问题?如果重要的话,我可以保证主线程不会做任何chdir'ing。

GetAttributes

1 个答案:

答案 0 :(得分:0)

最后,我发现perl正在维护某种仅适用于perl内置运算符的辅助cwd,而GetAttributes正在使用本机cwd。我不知道为什么会这样做或为什么它只发生在辅助线程中;我最好的猜测是perl试图模仿每个进程一个cwd的unix规则,并因为Win32::*模块不能正常运行而失败。

无论是什么原因,只要您正在进行Win32::*操作,就可以通过强制原生cwd与perl的cwd相同来解决问题,像这样:

use Cwd;
use Win32::FindFile qw/SetCurrentDirectory/;

...

SetCurrentDirectory(getcwd());

可以说,File::Find在Win32上运行时应该这样做。

当然这只会使"路径名太长"更糟糕的是,因为现在你访问的每个目录都是绝对路径SetCurrentDirectory的目标;试着用一系列较小的SetCurrentDirectory电话来解决这个问题,你必须找到一种方法来回到你来自哪里,当你甚至没有fchdir时这很难。