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


Автор: Jlekc 24.1.2006, 18:31
У меня создаеться новый трид (прослушка в клиент-серверном приложении).
При создании трида я передаю указатель на $self:

Код

sub initialized {
    (my $self, my $sock) = @_;
    $self->{"thread"} = threads->create("onReciev", $self);
    ....
}
sub onReciev {
    (my $self) = @_;
    ....
}



но адресс $self-а принятого после запуска трида отличаеться от реального адреса (вообщем дубликат).
Эт конечно мне совсем не подходит. Мне нужно передать указатель что фсе работало синхронно.
Как это зделать?


ЗЫ: К Модераторам: А почему таги code не вставляються?

Автор: korob2001 26.1.2006, 05:10
Что-то я не пойму вопроса. Поясни подробнее, чего ты хочешь добиться?

Автор: chaos 26.1.2006, 09:08
Цитата(Jlekc @ 24.1.2006, 18:31)
У меня создаеться новый трид (прослушка в клиент-серверном приложении).
При создании трида я передаю указатель на $self:

Код

sub initialized {
    (my $self, my $sock) = @_;
    $self->{"thread"} = threads->create("onReciev", $self);
    ....
}
sub onReciev {
    (my $self) = @_;
    ....
}



но адресс $self-а принятого после запуска трида отличаеться от реального адреса (вообщем дубликат).
Эт конечно мне совсем не подходит. Мне нужно передать указатель что фсе работало синхронно.
Как это зделать?


ЗЫ: К Модераторам: А почему таги code не вставляються?

а ты передавай референс(если я тебя конечно правельно понял)
пример
Код

#!/usr/bin/perl -w
use strict;

my $value;
GetValue(\$value);

========================
sub GetValue {
  my $RefValue = shift;
  $$RetValue = "value";
}


Автор: Jlekc 26.1.2006, 11:53
када передаю скалярные велечины или указатели на них все намана.
Но есе передаю екземпляр класа или даже референс, Пчемуто всегда создаеться дубликат((
При передачи референса это звучит как полный бред, но у меня это почемуто так

Автор: korob2001 26.1.2006, 20:45
А как ты создаёшь потоки?

Вот, для примера, написал программу, которая создаёт 5 потоков ( не путать с процессами ) и ведёт одновременный поиск в пяти текстовых файлах, при этом каждый поток ведёт поиск того, что ему заданно, в часности:
Код

Поток 1: Подсчитывает все вхождения o или O в файле sasser.txt
Поток 2: Подсчитывает все вхождения a или A в файле principles.txt
Поток 3: Подсчитывает все вхождения x или X в файле lanlinux.txt
Поток 4: Подсчитывает общее кол-во символов в файле nixdoc.txt
Поток 5: Подсчитывает общее кол-во целых чисел в файле nixdoc2.txt, число 15.8 будет воспринято 
               как два целых числа 15 и 8. Это не совсем верно, но сейчас не в этом суть. ;)))

Затем потоки собираются в один, после результаты поиска выводятся в STDOUT. Этот пример довольно растянут, но опять же это было сделано намерено, что бы он был более понятен.

Для того, что бы не озадачивать тебя поиском текста для файлов, прицепляю ZIP архив к этому посту. В нём находятся как текстовые файлы с текстом, так и сам исполняемый файл. Всё будет проходить довольно быстро, но если возникнет желание посмотреть на синхронизацию, то раскоментируй строки, которые я закоментировал в подпрограммах: tellLetters(), tellAll(), tellInt().
Код

#!/usr/bin/perl -w
use strict;
use IO::File;
use Thread;

my %threads = ();

# Пять файлов с текстом
my @files = qw( sasser.txt principles.txt lanlinux.txt nixdoc.txt nixdoc2.txt );

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#    Запускаем 5 потоков, каждый из которых будет искать своё в своём файле.   #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
$threads{O}   = Thread->new(\&tellLetters, $files[0], 'O');  # Подсчитывает 'Oo'
$threads{A}   = Thread->new(\&tellLetters, $files[1], 'A');  # Подсчитывает 'Aa'
$threads{X}   = Thread->new(\&tellLetters, $files[2], 'X');  # Подсчитывает 'Xx'
$threads{sim} = Thread->new(\&tellAll, $files[3]);           # Подсчитывает общее кол-во символов
$threads{int} = Thread->new(\&tellInt, $files[4]);           # Подсчитывает общее кол-во целых чисел

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#    Собираем потоки назад и посмотрим результаты поиска.                      #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
print "Total 'O' in file '$files[0]' is: "      . $threads{O}->join()   . "\n";
print "Total 'A' in file '$files[1]' is: "      . $threads{A}->join()   . "\n";
print "Total 'X' in file '$files[2]' is: "      . $threads{X}->join()   . "\n";
print "Total simbols in file '$files[3]' is: "  . $threads{sim}->join() . "\n";
print "Total integers in file '$files[4]' is: " . $threads{int}->join() . "\n";

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#   Подпрограмма будет подсчитывать кол-во заданных букв                       #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
sub tellLetters {
    my $file = shift;
    my $let  = shift;
    my $fh   = IO::File->new($file) or die "Can't open file '$file': $!\n";
    my $c    = 0;
    while (my $line = $fh->getline()) {
           if ( $line =~ s/$let/$c++/egi ) {
                #print "Letter '$let' in file '$file'\n";
                #sleep 1;
           }
    }
    $fh->close();
    return $c;
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#   Подпрограмма посчитывает общее кол-во символов                             #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
sub tellAll {
    my $file = shift;
    my $fh   = IO::File->new($file) or die "Can't open file '$file': $!\n";
    my $c    = 0;
    while (my $line = $fh->getline()) {
           $c += length($line);
           #print "Now I tell $c simbols in file '$file'\n";
           #sleep 1;
    }
    $fh->close();
    return $c;
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
#   Подпрограмма подсчитывает общеекол во цифр в тексте                        #
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
sub tellInt {
    my $file = shift;
    my $fh   = IO::File->new($file) or die "Can't open file '$file': $!\n";
    my $c    = 0;
    while ( my $line = $fh->getline() ) {
            if ( $line =~ s/\d+/$c++/eg ) {
                 #print "I find number in file '$file'\n\n";
                 #sleep 1;
            }
    }
    $fh->close();
    return $c;
}

Тебе нужно обратить особое внимание на то, как передаются аргументы в поток, а точене на такие строки:
Код

Thread->new(\&tellLetters, $files[0], 'O'); 

В отдельном потоке запускается подпрограмма tellLetters(), потоку передаём ссылку на неё. Далее через запятую передаём параметры в поток, в данном случае имя файла и искомую строку. Для работы с файлами я использовал модуль IO::File, для того, что бы было проще переписать этот пример для работы с сокетами, так как этот класс является производным от класса IO::Handle, так же как и класс IO::Socket. По нормальному ещё и не мешало бы блокировать потоки, если они используются для записи, с помощью lock().

Насколько я понял задачу, ты хочешь организовать прослушку на сервере, т.е. когда подключается клиет, то для него создаётся отдельный поток, в котором клиент и работает. Основной же поток так и продолжает ожидать нового подключения, если оно будет, то будет создан ещё один поток. Когда клиент отключается, то его поток соединяется обратно с основным потоком?

Не знаю насколько верны мои огадки. Вобщем пробуй, если что-то не так или не понятно, пиши.

Автор: Jlekc 27.1.2006, 18:48
Догадки твои верны. Но приведенный тобой пример не совсем точен.

Клиент скидуеться на отдельный поток и запускаеться прослушка сообщениый от него.
Пакет присланный клиентом может быть одресован определенному клиенту. Знач должен быть зашареный объект, кторой ведет лист клиентов, и ряд утилитных фукнций.
При создании клиента и вещанья его метода onReciev в отдельном триде на прослушку, как аргумент для создания трида нуна передать указатель на самого себя.
Я передавал референс, но почемуто создавался клон. Воот тут и проблема.

Хтя, быть может это от того что я сижу на Винде. Всеже перл расчитан на юникс.


ЗЫ: Спасибо за помощь но тема исцерпана. Хтя разобраться былоб интересно.
Щас взялся за другую задачу. Этой занимаеться другой чел. Посмотрим как спаравиться.

Автор: rcdimon 27.2.2006, 13:51
У меня есть огромный список URL'ов, с которых нужно скачать страницы... Надо что бы программа качала их в несколько потоков. Какое число потоков оптимально? Например 10 потоков.. Как мне контролировать количество запущенных потоков, что бы их было всегда 10. Когда один отработал- запускался бы новый...

Код

#!/usr/perl58/bin/perl 

use threads;

for ($i=1; $i < 110; $i++){
    @thr[$i] = threads->new(\&haha, $i);
    print @thr[$i]->join();
}
    
    
sub haha {
        my $a = shift;
        return 'hello ' . $a . "\n";
}


тут, как я понимаю, никакого контроля не ведется...

Например есть у меня массив @urls. В котором может быть большое количество элементов. Каждый элемент- URL адрес. Как мне запускать одну и ту же подпрограмму, что бы в памяти было определенное количество потоков. Каждому новому потоку передавать новый элемент этого массива в качестве параметра. И выполнять работу, пока все элементы массива не будут проработаны.
Добавлено @ 13:53
Кстати подпрограммка, которую я хочу многопоточно запускать довольно немаленькая... использует несколько модулей Perl. А на сервере стоит ограничение- 50 метров ОЗУ на программу....

Автор: rcdimon 1.3.2006, 11:33
Люди! Подскажите smile

Автор: sharq 1.3.2006, 14:17
rcdimon, к сожалению, я thread'ы на perl не программировал, не приходилось.
Могу рассказать про fork (распараллеливание отлично работает под nix), где-то здесь на форуме приводил функцию, которая скачивает страницы через прокси.

smile
Добавлено @ 14:20
По тредам - perldoc Thread, perldoc threads. smile

Автор: rcdimon 1.3.2006, 14:29
Отлично. Мне не особо важно как будет происходить распаралеливание. Мне надо что бы просто подпрограмма, в задачу которой как раз входит закачка документов из сети и их обработка, запускалась многопоточно.

покажи пожалуйста пару примеров, или дай ссылку! Мне как я уже говорил надо поддерживать в памяти 10 потоков для обработки большого количества ссылок.

Цитата

распараллеливание отлично работает под nix


А в винде хоть немного работает? Я пишу на винде, но потом будет работать во FreeBSD... Хорошо бы что бы в винде работало хотя бы для разработки
Добавлено @ 14:29
И еще надо что бы не использовалось никаких нестандартных модулей

Автор: sharq 1.3.2006, 14:34
rcdimon,

Цитата(rcdimon @ 1.3.2006, 15:29 Найти цитируемый пост)
А в винде хоть немного работает? Я пишу на винде, но потом будет работать во FreeBSD... Хорошо бы что бы в винде работало хотя бы для разработки


Цитата(rcdimon @ 1.3.2006, 15:29 Найти цитируемый пост)
покажи пожалуйста пару примеров, или дай ссылку!


perldoc -f fork, perlfork и посмотри особенности использования под Windows (в обще под win32 не работает).

а пример закачки страницы ищи на форуме.

smile

Автор: rcdimon 1.3.2006, 15:09
Цитата

а пример закачки страницы ищи на форуме.


Искал- не нашел

Автор: sharq 1.3.2006, 15:18
rcdimon, плохо ищешь. smile
http://forum.vingrad.ru/index.php?showtopic=72105

smile smile

Автор: rcdimon 1.3.2006, 15:33
Отлично.. единственное, чего я там не нашел- так это распаралеливание закачек.... а я именно это и просил

Автор: korob2001 1.3.2006, 23:25
Создай массив с нужным числом потоков.
В примере выше, я сохранял потоки в хеше. Если посмотришь код, думаю создать массив потоков не составит особого труда. Единственное, что нужно добавить это код, который будет контролировать остались ли ещё ссылки в массиве или нет. Если да, то создаёшь поток в том элементе, который только что соединил, если нет, то просто соединяешь поток и ожидаешь завершения работы остальных потоков.
Если я чего-то не понял, поясни подробнее, чего ты хочешь добиться? Ты хочешь создавать зеркала html страниц или же ты хочешь заливать большие файлы в несколько потоков? Как например это делает ReGet Deluxe?

Автор: rcdimon 2.3.2006, 10:48
Неа. я хочу качать из инета небольшие файлы. но их много. Спасибо за совет. сегодня попробую

Автор: rcdimon 4.3.2006, 12:47
как узнать что поток отработал?

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