我使用File::Find
來遍歷目錄樹和Win32::File
的GetAttributes
函數來查看在其中找到的文件的屬性。這工作在一個單線程程序。GetAttributes在子線程中使用錯誤的工作目錄
然後我把目錄遍歷到一個單獨的線程,它停止工作。 GetAttributes
在「系統找不到指定的文件」的每個文件上都失敗,作爲$^E
中的錯誤消息。
我將問題追溯到File::Find
使用chdir
這一事實,並且顯然GetAttributes
未使用當前目錄。我可以通過傳遞一個絕對路徑來解決這個問題,但是然後我可以運行到路徑長度限制,並且在腳本運行的地方肯定會出現長路徑,所以我真的需要利用chdir
和相對路徑。
爲了說明問題,這裏是它會在當前目錄中的文件的腳本,在子目錄另一個文件,CHDIR對子目錄,並查找文件3種方式:system("dir")
,open
和GetAttributes
。
當腳本不帶參數運行,dir
顯示子目錄,open
發現在子目錄中的文件,並GetAttributes
成功返回其屬性。當與--thread
一起運行時,所有測試均以子線程完成,並且dir
和open
仍然有效,但GetAttributes
失敗。然後它調用GetAttributes
對原始目錄(我們已經chdir'ed了)的文件,它找到了一個!不知怎的,GetAttributes
正在使用進程的原始工作目錄 - 或者可能是主線程的工作目錄 - 與所有其他文件操作不同。
我該如何解決這個問題?我可以保證主線程不會做任何chdir'ing,如果這很重要。
use strict;
use warnings;
use threads;
use Data::Dumper;
use Win32::File qw/GetAttributes/;
sub doit
{
chdir("testdir") or die "chdir: $!\n";
system "dir";
my $attribs;
open F, '<', "file.txt" or die "open: $!\n";
print "open succeeded. File contents:\n-------\n", <F>, "\n--------\n";
close F;
my $x = GetAttributes("file.txt", $attribs);
print Dumper [$x, $attribs, $!, $^E];
if(!$x) {
# If we didn't find the file we were supposed to find, how about the
# bad one?
$x = GetAttributes("badfile.txt", $attribs);
if($x) {
print "GetAttributes found the bad file!\n";
if(open F, '<', "badfile.txt") {
print "opened the bad file\n";
close F;
} else {
print "But open didn't open it. Error: $! ($^E)\n";
}
}
}
}
# Setup
-d "testdir" or mkdir "testdir" or die "mkdir testdir: $!\n";
if(!-f "badfile.txt") {
open F, '>', "badfile.txt" or die "create badfile.txt: $!\n";
print F "bad\n";
close F;
}
if(!-f "testdir/file.txt") {
open F, '>', "testdir/file.txt" or die "create testdir/file.txt: $!\n";
print F "hello\n";
close F;
}
# Option 1: do it in the main thread - works fine
if(!(@ARGV && $ARGV[0] eq '--thread')) {
doit();
}
# Option 2: do it in a secondary thread - GetAttributes fails
if(@ARGV && $ARGV[0] eq '--thread') {
my $thr = threads->create(\&doit);
$thr->join();
}