Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > семафор, синхронизация процессов


Автор: FooBar 30.7.2008, 14:07
Здравствуйте, у меня вот такой вопрос, я открываю файл в родительском процессе, далее fork создаю 3 потомка которые читают из этого файла строки и записывают их каждый в свой файл:

Код

#!/usr/bin/perl
use warnings;
use strict;
use IPC::SysV qw(IPC_CREAT IPC_PRIVATE IPC_RMID);

open(FILE, '<4test') || die $!;

my $id = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT ) || die $!; #создаем семафор
semop($id, pack("s3", 0, +1, 0)) || die $!; #открываем его

my (@childs, $pid);
for (0..2)
{
    $pid = fork; #тут собственно форкаемся
    die $! unless defined $pid;
    unless ($pid)
    {
        open(TMP, '>/tmp/'.$$) || die $!; #и открываем файл
        while (1)
        {
            semop($id, pack("s3", 0, -1, 0)) || die $!; #опускаем семафор
            my $string = <FILE>;                                #читаем строку
            semop($id, pack("s3", 0, +1, 0)) || die $!; #поднимаем семафор
            last unless defined $string;
            print TMP $string;
        }
        close TMP;
        close FILE;
        exit(0)
    }
    else
    {
        push(@childs, $pid)
    }
}

close FILE;
waitpid($_, 0) for (@childs); #ждем детишек

semctl($id, 0, IPC_RMID, 0) || die $!; #удаляем семафор



а вот что я наблюдаю в файлах:
Код

один файл:
5
add5efc3f8de35d6208dc6fc154b59d3
другой:
2aeb3faaf76e04a953f9369bdeecbeb9
af063d75c14a83239da1b396
545a2296a05d382354887c2886ea50d5
и т.д.

то есть строки повредились

исходный тестовый файл был создан таким образом:
Код

use MD5;

for $i (1..300000) {
    print MD5->hexhash($i)."\n";
}



с отключением буферизации я эксперементировал, не помогло если просто без семафоров читать, то результат такой же, может быть здесь стоит применить flock, но кукбук говорит что блокировка исчезает только после закрытия файла, что в данном случае недопустимо.
собственно вопрос в том как добиться нормально чтения строк из файла несколькими процессами с сохранением смещения

Автор: sir_nuf_nuf 30.7.2008, 14:39
FooBar, зачем вам семафор ?
Читать можно и без блокировки файла.
у всех процессов будет правда общее смещение в файле...

Автор: FooBar 30.7.2008, 14:51
sir_nuf_nuf,
>У каждого процесса будет свое смещение в файле.
мне то как раз нужно чтобы у них было общее смещение, то есть если первый процесс прочел первую строку из файла, то второй прочитает вторую, и так далее

Автор: sir_nuf_nuf 30.7.2008, 15:13
упс.. я вам наврал =)
все как раз наоборот - у них будет общий файловый дескриптор, и смещение будет общим.
сейчас подумаю..

Автор: arto 30.7.2008, 15:30
my $cnt = 0
my @a = grep { ++$cnt/3 == 0 } <F>;

my @a = grep { ++$cnt/3 == 1 } <F>;

my @a = grep { ++$cnt/3 == 2 } <F>;

?

Автор: IceSunrise 30.7.2008, 15:34
вы хотите, чтобы они строго последовательно считывали строки?

Автор: sir_nuf_nuf 30.7.2008, 15:40
FooBar, я так подумал, что не получится открывать файл один раз, а потом его дескриптор наследовать при форке.
Вот почему:
для чтения вы используете оператор <>
этому оператору нужно как-то найти конец строки в файле, поэтому он читает блоками 
(не проверял, но здравый смысл подсказывает, что не посимвольно =))
Когда считывается блок из файла - есть вероятность прочитать более одной строки,
при это смещение увеличивается и указывает на середину следующей строки.
Поэтому следующий процесс получает битую строку.

Отключение буферизации может и не помочь в таком случае.

Решения видно 2:

а) каждый потомок открывает свой дескриптор и читает из него. Выбирает каждую 3ю строку, как показал arto
б) читать не построчно, а блоками фиксированной длинны.

Автор: FooBar 30.7.2008, 16:02
sir_nuf_nuf, спасибо, похоже вы прояснили ситуацию, меня интересовало почему так происходит, а для практической реализации можно использовать и другие алгоритмы
IceSunrise, задумка была в считывании построчно на ходу (не читая заранее весь файл) и распределении между процессами, примерно так:
1 aaa
2 bbb
3 ccc
4 ddd
5 eee
6 fff

1 процесс:
aaa
ccc
2 процесс:
bbb
ddd

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)