И еще раз исправил программист модуль MkDir из предыдущей задачи, теперь существование каталога проверяется правильно.
MkDir4.pm (файл скачивается):
package MkDir4;
use strict;
use warnings;
=head1 NAME
MkDir4 -- рекурсивное создание каталогов
=head1 SYNOPSIS
use MkDir4;
MkDir4::mkdir_recursive("test/a");
MkDir4::mkdir_recursive("/tmp/test/b");
=head1 DESCRIPTION
Модуль предоставляет функцию mkdir_recursive для рекурсивного создания каталогов.
Модуль предназначен для Unix-подобных систем с разделителем в именах каталогов "/" и корневым каталогом /.
=cut
sub _mkdir
{
my ($dir) = @_;
unless (-d $dir){
mkdir $dir or die "can't create dir $dir: $!";
}
}
sub mkdir_recursive
{
my $path = shift or die;
my @parts = split "/", $path;
my $dir = shift @parts;
_mkdir $dir unless $dir eq '';
for my $d (@parts){
$dir .= "/$d";
_mkdir $dir;
}
}
1;
И долгое время все было хорошо… Пока Очень Полезный Скрипт, использующий этот модуль, не стал форкаться и работать параллельно.
А когда скрипт стал форкаться и работать в несколько потоков,
mkdir_recursive
стала время от времени умирать с сообщением о невозможности создать каталог,
хотя потом оказывалось, что каталог все-таки создан.
Можно скачать упрощенный пример использования mkdir_recursive
из параллельных процессов.
Текущая версия mkdir_recursive
подвержена
гонкам (race condition):
между проверкой существования каталога
и вызовом mkdir
другой процесс может успеть
создать каталог, и mkdir
завершится неудачей
(каталог уже существует), хотя по существу
работа выполнена успешно: каталог есть (хоть и создан из
другого процесса).
Между прочим, модуль File::Path::Tiny с CPAN тоже подвержен такой проблеме по крайней мере до версии 0.5. А вот File::Path – нет, не подвержен.