Все задачи

Созидательный труд-4

23 Sep 2013

И еще раз исправил программист модуль 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 стала время от времени умирать с сообщением о невозможности создать каталог, хотя потом оказывалось, что каталог все-таки создан.

Подсказка-2

Показать

Можно скачать упрощенный пример использования mkdir_recursive из параллельных процессов.

Разоблачение

Показать

Текущая версия mkdir_recursive подвержена гонкам (race condition): между проверкой существования каталога и вызовом mkdir другой процесс может успеть создать каталог, и mkdir завершится неудачей (каталог уже существует), хотя по существу работа выполнена успешно: каталог есть (хоть и создан из другого процесса).

Между прочим, модуль File::Path::Tiny с CPAN тоже подвержен такой проблеме по крайней мере до версии 0.5. А вот File::Path – нет, не подвержен.