2010-09-10 51 views
6

我最近繼承了別人寫過的一些代碼。在Perl中不關閉目錄句柄有什麼含義?

我發現在代碼中無處不在,一個目錄被打開以供閱讀,它從未關閉,因爲原始開發人員有語法問題 - 他正在使用close函數嘗試關閉目錄句柄而不是closedir函數。

的代碼是這樣的:

opendir(DIR, $dir) or die "Cannot open $dir: $!\n"; 
@files = readdir(DIR); 
close(DIR); 

(這是另一個好點,在有關檢查close函數的返回Perl的最佳實踐(208278頁)由如果close返回了。在這種情況下,它會失敗,「壞文件號」)。

我已經改變了這個closedir,但它讓我開始想知道:由於目錄句柄從未關閉,負面影響是什麼保持長時間打開的目錄句柄?

該程序較大(3,500行代碼),運行一段時間(5-10分鐘),並且該程序的多個實例同時運行。對於上例中的此目錄,$dir對於所有實例都是相同的值。如果該程序的10個實例同時運行,則它們在同一個目錄下持有5分鐘或更長時間的開放目錄句柄。我相信當程序結束時,Perl會自動關閉目錄句柄,但最好的做法是儘快關閉它。

更明顯的是,如果將文件句柄打開會導致問題(特別是對於可以寫入的文件句柄),但通過不關閉目錄句柄會發生什麼壞事?

我問的原因是因爲這個程序試圖創建一個文件(在上面的$ dir定義的目錄中)有一個奇怪的情況。文件名中嵌入了PID,所以文件已經存在的可能性較小,但Perl無法打開文件進行寫入,因爲它表示它已經存在。當我們查看目錄時,該文件不存在。我想知道是否所有打開的目錄句柄在這個目錄可能會導致這樣的問題?

我不確定操作系統是否有所作爲,但該程序在AIX上運行。

在此先感謝,並且開心的星期五!

回答

11

您浪費了一個目錄描述符 - 可能會將其視爲文件描述符。如果您的程序打開了足夠的目錄以用完文件描述符,它最終會傷害到您。否則,這是相當無害的,雖然不夠理想。它使得系統(和Per​​l)保持它可能會釋放的資源。

如果目錄句柄是一個局部變量,而不是一個普通的DIR風格的名字,你可能會在你身後清理Perl。參見opendir其中說:

打開一個名爲EXPR的目錄,以便通過readdir,telldir,seekdir,rewinddir和closedir進行處理。如果成功則返回true。 DIRHANDLE可能是一個表達式,其值可以用作間接dirhandle,通常是真正的dirhandle名稱。如果DIRHANDLE是一個未定義的標量變量(或數組或散列元素),則該變量被賦予一個新的匿名dirhandle的引用。 DIRHANDLE具有獨立於FILEHANDLE的獨立命名空間。

+1

即使在今天,一些操作系統對文件描述符(我正在查看*你*,solaris和默認設置64-256)非常吝嗇。 – mob 2010-09-10 18:35:25

+8

@mobrule - 我很抱歉,由於沒有可用的文件描述符,我無法發佈您的評論 - 此致,StackOverflow Solaris後端.... – DVK 2010-09-10 19:50:17

7

不會有任何嚴重的後果。從內核本身來看,內存使用量會有輕微的增加,它不能釋放它在內部使用的迭代器來遍歷目錄條目列表,並且可能還會從perl端進行循環。

此外,只要目錄的任何描述符仍處於打開狀態,數據就不能真正從文件系統中刪除。如果其他外部進程將刪除您擁有該句柄的目錄,它將停止出現在未來的目錄列表中,但數據仍然必須保存在磁盤上,並且仍然可以通過打開的句柄進行訪問。例如,這可能導致磁盤使用中出現奇數。

另請注意,您不必手動關閉所有手柄。當使用詞法文件句柄,收盤就自動發生,因爲最後一個關於手柄消失:

{ # new scope 
    opendir(my $handle, ...) or ...; 
    ... 
} # implicit closedir happens here 
6

這是一個教訓,始終使用的詞彙文件級(和目錄 - )處理 - 詞法手柄自動關閉當他們超出範圍。

所以,如果你使用了舊式的glob句柄,或者所有的代碼都在一個沒有子程序或其他範圍的平面腳本中,你只會浪費描述符(如Jonathan所描述的)。使用良好的編程習慣和無意中的錯誤將更少:)

+0

此opendir在main中,因此它在全局範圍內...您是絕對正確的 - 良好的編程習慣肯定會減少無意的錯誤! – BrianH 2010-09-10 18:39:14

+1

根據你的代碼,無論如何你都使用了一個裸句柄。除非你明確地定位它們,否則它們總是在全局範圍內。 – rafl 2010-09-10 18:41:58