Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2009.03.29;
Скачать: [xml.tar.bz2];

Вниз

Организация работы потоков   Найти похожие ветки 

 
Тимоха   (2009-02-02 08:20) [0]

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

Необходимо реализовать работу функций программы с использованием потоков.

Более подробное описание задачи потоков:

При старте программы возможны два варианта:
(А).Программа запускается впервые,поэтому запускается поток ThrStartFirst. Этот поток скачивает с сайта страницу, парсит нужные данные и добавляет их в более расширенный компонент listbox(у листбокса есть свойства text,text1,text2,text3). В то время как работает ThrStartFirst, запускается следующий поток ThrStratAnalys, который берет по очереди каждый итем листбокса, вытаскивает свойство text и скачивает страницу с интернета, уже анализируя полученные данные и сохраняя в определенной структуре в файл.В это же время должен работать еще один поток ThrUpdate. Он скачивает всю туже страницу и наблюдает за появлением новых данных,удалением тех которые уже удалены с той страницы в интернете, и изменением каких то данных.( запускаться поток должен через определенное заданное время)

Вариант (В). Программа запущенна не впервые. В листбокс заносятся данные из сохраненных файлов(учитывая что вариант А полностью отработал в предыдущей загрузке, если нет то скачиваются файлы, которые не были скачаны в пером запуске А). Как только данные занесены, а это происходит весьма быстро так как файлы находяятся на диске в формате txt, то запускается поток ThrUpdate, выполняет те же операции что и в варианте А. Идеально было, если б таких ThrUpdate было больше одного(т.е.ThrUpdate1,2,3,4... которые выполняли свои функции с данными, не обязательно изменявшие данные в листбоксе).

Изучал работу критических секций,мьютексов, семафоров и других вариантов синхронизации. Но понять пока еще трудно. Надеюсь на помощь в создании алгоритмов. Надеюсь услышать советы: что лучше использовать в моем случае, на что обратить внимание.
P.S. Программа будет работать с моим сайтом. Для скачивания содержимого страниц используется idhttp.
Заранее благодарен.


 
Сергей М. ©   (2009-02-02 08:25) [1]


> понять пока еще трудно


Что конкретно ?


 
Тимоха   (2009-02-02 08:30) [2]

Перед тем как начать писать программу с потоками, надо определить схему: какие потоки будут, как будут взаимодействовать и т.д. Пока трудности со схемой. Ну и с реализацией тоже.


 
Тимоха   (2009-02-02 08:41) [3]

Для реализации поставленной задачи критической секции хватит? Хочется чтобы программа работала без ошибок (в плане потоков), и потоки правильно освобождались.


 
KSergey ©   (2009-02-02 08:46) [4]

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

Собственно основное на что надо обращать внимание: чтобы
а) одни и те же данные не модифицировались из разных потоков одновременно; если надо модифицировать из разных потоков - обкладываем объектами сихронизации.
б) один поток не читал еще не готовые полностью данные другого потока; хотя это отчасти разновидность пункта а)

Объекты синхронизации вибираем по месту, сказать "вообще" - невозможно, ина че бы их не было столько разнообразных.
Всегда вибираем самые "легкие" из тех, что подходят для конкретной задачи.


 
Сергей М. ©   (2009-02-02 08:53) [5]


> Для реализации поставленной задачи критической секции хватит?


Если исключить потенциальную возможность обращений доп.потоков к визуальным VCL-контролам, то, возможно, и хватит.


 
Тимоха   (2009-02-02 09:33) [6]

Listbox служит выводом информации для пользователя, как я могу от него отказаться:))))))))))


 
Сергей М. ©   (2009-02-02 09:39) [7]


> Тимоха   (02.02.09 09:33) [6]


А никто и не заставляет тебя от него отказываться.
Вопрос в том, что доп.тредам в условиях VCL-приложения крайне нежелательно знать ни про какие листбоксы и прочие UI-контролы.


 
Медвежонок Пятачок ©   (2009-02-02 09:40) [8]

(А).Программа запускается впервые,поэтому запускается поток ThrStartFirst. Этот поток скачивает с сайта страницу, парсит нужные данные и добавляет их в более расширенный компонент listbox(у листбокса есть свойства text,text1,text2,text3). В то время как работает ThrStartFirst, запускается следующий поток ThrStratAnalys, который берет по очереди каждый итем листбокса, вытаскивает свойство text и скачивает страницу с интернета, уже анализируя полученные данные и сохраняя в определенной структуре в файл.В это же время должен работать еще один поток ThrUpdate. Он скачивает всю туже страницу и наблюдает за появлением новых данных,удалением тех которые уже удалены с той страницы в интернете, и изменением каких то данных.( запускаться поток должен через определенное заданное время)

Дурь несусветная.
Три разных потока-близнеца "скачивают страницы с инета"


 
Медвежонок Пятачок ©   (2009-02-02 09:45) [9]

Надеюсь услышать советы: что лучше использовать в моем случае, на что обратить внимание.

что имеенно использовать - неважно.
главное перестать использовать свой генератор дури и воспользоваться мозгом.


 
Тимоха   (2009-02-02 09:59) [10]

Медвежонок Пятачок ,я не претендую на статус прошаренного. Поэтому и пишу в форуме для начинающих. Прошу писать по теме. О генераторе дури можем поговорить в разделе "Прочее". Если есть дельные мысли по тому как правильней сделать, можете написать здесь - не стесняйтесь. Я вам буду только благодарен.
> Сергей М


Использовать буфер для хранения данных, а затем vcl потоком вытаскивать из буфера данные?


 
Сергей М. ©   (2009-02-02 10:01) [11]


> Тимоха   (02.02.09 09:59) [10]


Это уж как угодно.


 
Медвежонок Пятачок ©   (2009-02-02 10:02) [12]

чтобы услышать дельные мысли, надо внятные вопросы задавать, а не просто туманно рассуждать "а что бы такое-етакое позаковыристее мне написать ?"

в чем конкретная проблема твоя?


 
Тимоха   (2009-02-02 10:20) [13]

Не могу продумать последовательность работы потоков и выбрать правильный метод синхронизации для моей задачи.


 
Медвежонок Пятачок ©   (2009-02-02 10:21) [14]

С этим не сюда. С этим к терапевту.


 
Медвежонок Пятачок ©   (2009-02-02 10:24) [15]

последовательность работы потоков

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


 
Тимоха   (2009-02-02 10:31) [16]

Ок. Имел ввиду параллельность.


 
Riply ©   (2009-02-02 10:40) [17]

> [0] Тимоха   (02.02.09 08:20)
> Более подробное описание задачи потоков:

Села и честно пыталась понять что и как ты хочешь сделать.
Не сумела. Может попробовать пойти от простого к сложному ?
Напрмер, реализовать все без потоков. Потом отдельную задачу вынести в поток.
И т.д. ?


 
Медвежонок Пятачок ©   (2009-02-02 10:40) [18]

а теперь спроси себя, зачем тебе три разных класса потоков, которые на 90% делают одно и тоже


 
Тимоха   (2009-02-02 10:47) [19]

Riply, вообщем то так и делаю. Сначала сделал без потоков. Теперь пытаюсь с ними.

Медвежонок Пятачок, потоки скачивают разные страницы, и делают разные парсинги и анализы.


 
Медвежонок Пятачок ©   (2009-02-02 10:49) [20]

Понятно.
Чернила для седьмого класса. Чернила для седьмого класса "Б" и чернила для седьмого класса "Б" для вторника.


 
Медвежонок Пятачок ©   (2009-02-02 10:51) [21]

а если вдруг требуется поддержка прокси, то трудолюбиво переколбашиваем все три класса.
а чо, времени у студента вагон, и старость за горами.


 
Тимоха   (2009-02-02 10:57) [22]

вот код, который запускает поток:
Thread_Start_First := TThread_Start_First.Create;
   Thread_Start_First.FreeOnTerminate := True;
   try
     with Thread_Start_First do
     begin
       OnTerminate := HandleTerminate;
       Resume;
     end;
   except on EConvertError do
     begin
       Thread_Start_First.Free;
       ShowMessage("ERROR");
     end;
   end;




 
Медвежонок Пятачок ©   (2009-02-02 11:03) [23]

из кода видно, что потоку ничего не передается в качестве параметров.
то есть он "знает" урл с которого качать, знает куда совать выкачанные данные и так далее.

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


 
Сергей М. ©   (2009-02-02 11:06) [24]


> Тимоха   (02.02.09 10:57) [22]
>

Плохой код. Очень плохой.


 
Anatoly Podgoretsky ©   (2009-02-02 11:06) [25]

> Тимоха  (02.02.2009 10:57:22)  [22]

И гадай Вася, что там за ошибка.


 
Медвежонок Пятачок ©   (2009-02-02 11:09) [26]

Зачем гадать? У нас же есть суперинформативное
ShowMessage("ERROR");


 
Сергей М. ©   (2009-02-02 11:12) [27]


> Тимоха   (02.02.09 10:57) [22]


Ты вообще-то задумывался над тем, кто-что и по каким причинам может возбудить искл-е EConvertError при выполнении тех операторов, которые у тебя фигурируют в with-блоке ?


 
Riply ©   (2009-02-02 11:18) [28]

> [22] Тимоха   (02.02.09 10:57)

Хотела было тебя съесть с потрохами за этот код,
но подумала, вдруг другие тоже голодные и не стала :)


 
Сергей М. ©   (2009-02-02 11:22) [29]


> Riply ©   (02.02.09 11:18) [28]


Колобка на всех хватит)


 
Тимоха   (2009-02-02 11:22) [30]

поток создается так
constructor TThread_Start_First.Create;
begin
 inherited Create(True); //Созданный поток создается в приостановленном состоянии
 FreeOnTerminate := True; //Поток освободит ресурсы при окончании работы
 Self.Priority := tpNormal; //Очень высокий приоритет
 Resume;
end;


procedure TThread_Start_First.Execute;
begin
...
syncronize(get_page);
...
syncronize(updateresults);
end;

procedure TThread_Start_First.get_page;
begin
 Page := HTTP.Get(URL);
end;

procedure TThread_Start_First.updateresults;
begin
form1.listbox1.items.add(...);
...
end;


 
Сергей М. ©   (2009-02-02 11:24) [31]


> Тимоха   (02.02.09 11:22) [30]


Тихий ужас.
Тяжелое наследие Архангельского.


 
Тимоха   (2009-02-02 11:24) [32]

Ладно, как должен выглядеть код правильно?


 
Медвежонок Пятачок ©   (2009-02-02 11:25) [33]

Ууууу.....................

А сам поток-то зачем тогда?


 
Медвежонок Пятачок ©   (2009-02-02 11:26) [34]

не. срочно к терапевту, или лучше сразу в морг.


 
Сергей М. ©   (2009-02-02 11:27) [35]


> Тимоха   (02.02.09 11:24) [32]


> как должен выглядеть код правильно?


Ты не ответил на [27].
Бессмысленно рассуждать о "правильности", если ты не хочешь думать самостоятельно.


 
Тимоха   (2009-02-02 11:29) [36]

уууууу- так работает мотор))))))

Про Архангельского не раз видел плохие отзывы, но при этом никто "правильного" кода не приводит :(

 Potok := TThread.Create(true);
 Potok.FreeOnTerminate := true;
 Potok.Priority := tpLowest;
 Potok.Resume;


так будет вернее?


 
Тимоха   (2009-02-02 11:31) [37]


> Сергей М

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


 
Сергей М. ©   (2009-02-02 11:31) [38]


> Тимоха   (02.02.09 11:29) [36]


см. [27]
Пока не ответишь, дальше не поедем.


 
Сергей М. ©   (2009-02-02 11:32) [39]


> Тимоха   (02.02.09 11:31) [37]


Еще раз прочитай вопрос в [27] !


 
Тимоха   (2009-02-02 11:34) [40]

Задумывался. В моем случае ничто и никто.


 
Медвежонок Пятачок ©   (2009-02-02 11:35) [41]

procedure TThread_Start_First.Execute;
begin
...
syncronize(get_page);
...
syncronize(updateresults);
end;


Код твоего чудесного вторичного потока на 99% работает в контексте главного потока.
Зачем тебе вообще поток понадобился?


 
Сергей М. ©   (2009-02-02 11:37) [42]


> Задумывался. В моем случае ничто и никто.


Тогда зачем нужен блок перхвата-обработки этого исключения ?


 
Тимоха   (2009-02-02 11:38) [43]

Чтобы был доступ к VCL, не было тормозов, и работали сразу несколько процедур параллельно.


 
Тимоха   (2009-02-02 11:39) [44]


> Тогда зачем нужен блок перхвата-обработки этого исключения
> ?


Скопировал с примера. Забыл убрать.


 
sniknik ©   (2009-02-02 11:40) [45]

> но при этом никто "правильного" кода не приводит :(
вот тут ты врешь...  и там главное не код, главное понять в чем к нему претензии, и самому так не делать. вот нафига тебе тут поток если вся работа идет в основном?

р.с. приведи какую нибудь ссылку с плохими отзывами... посмотрим.

> так будет вернее?
у тебя в моторе ломик застрял, из-за которого он не заводится, а ты машине фары меняешь и спрашиваешь "может так заведется?".


 
sniknik ©   (2009-02-02 11:43) [46]

> и работали сразу несколько процедур параллельно.
при твоем подходе они все будут стоять в очереди у главного... т.е. куча усилий и пшик в итоге.


 
Сергей М. ©   (2009-02-02 11:43) [47]


> Забыл убрать


Так.
Что еще ты забыл убрать ?


 
Медвежонок Пятачок ©   (2009-02-02 11:51) [48]

Смело делай Shift+Del на папке проекта. А Архангельского, или откуда там ты копировал примеры - на растопку.

Потом все сначала и уже с применением мозга.


 
Тимоха   (2009-02-02 12:12) [49]

Спасибо всем за ответы, очень ценю вашу помощь!
Решил попробовать по другому.
Код формы:
procedure TForm1.btn1Click(Sender: TObject);
var
 potok: TTest;
begin
 potok := TTest.Create(true);
 potok.FreeOnTerminate := true;
 potok.Priority := tpLowest;
 potok.Resume;
end;


код потока:
uses
 Classes, idhttp, unit1, StrUtils;

type
 TTest = class(TThread)
 private
   http: tidhttp;
   page: string;
   { Private declarations }
 protected
   procedure update;
   procedure Execute; override;
 end;

implementation

procedure TTest.Execute;
begin
 http := TIdHTTP.Create(nil);
 http.ProtocolVersion := pv1_1;
 page := http.Get("http://www.delphimaster.ru/cgi-bin/forum.pl?n=18");
 Synchronize(update);
 http.Free;
end;

procedure TTest.update;
var
 i, index, count: Integer;
 s:string;
begin
 count := 0;
 index := PosEx("<nobr>", page, count);
 repeat
   count := PosEx("
", page, index);
   s := Copy(page, index+9, count - index - 9);
   Form1.lst1.Items.Add(s);
   index := PosEx("<nobr>", page, count);
 until index = 0;

end;

Ругайте :)


 
Тимоха   (2009-02-02 12:15) [50]

По нажатию на кнопку, создаю поток, говорю ему чтобы сам освободился, ставлю приоритет ниже vcl"кого, запускаю.

В потоке: создаю http, скачиваю страницу, использую syncronize, в котором ищу имена авторов и добавляю их на форму.


 
Медвежонок Пятачок ©   (2009-02-02 12:17) [51]

двойка за хардкодед урл.

за Form1.lst1.Items.Add(s); в методе потока расстрел через повешение.


 
Сергей М. ©   (2009-02-02 12:21) [52]


> Тимоха


Уже ощутимо лучше.

Но:

1. А если запрашиваемый ресурс окажется недоступным ?
2. А если завтра Form1.lst1 превратятся во что-то другое или совсем исчезнут из проекта ?


 
Медвежонок Пятачок ©   (2009-02-02 12:27) [53]

TTest = class(TThread)
...
constructor CreateIt(const AURL : string; AList : TString); override;
end;

Только все равно это будет неправильно.
Нельзя просто взять кусок программы и вынести его в поток.
Выносить нужно со смыслом и чтобы польза была.

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

Номальные люди так код не структурируют.


 
Тимоха   (2009-02-02 12:40) [54]


> Сергей М.


А если попробовать так, создаем буфер, поток в него сохраняет данные и посылает форме сообщение, а та на сообщения добавляет содержимое буфера в листбокс?


> Медвежонок Пятачок


Не совсем понятно что оставлять в основном потоке, а что выносить в раба.
Можете привести пример?


 
Медвежонок Пятачок ©   (2009-02-02 12:46) [55]

Поток должен тягать урл ресурс и уметь возвращать результат вызываеющему коду и больше ничего не должен делать.
тогда он будет полезен с точки зрения повторного использования кода.

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

Т.е. никому не нужный мартышкин труд.
Будет десять потоков-близнецов.
Однажды ты решишь перейти с инди на что-то другое или просто на другую версию инди где изменена внутренняя иерархия классов - и привет.
Засучивай рукава и модифицируй код всех десяти классов.


 
Тимоха   (2009-02-02 12:51) [56]

Т.е. вы предлагаете в поток вывести только скачку страницы, а результат скачивание отдавать основному потоку и все функции и процедуры, которые парсят текст должны находится тоже в основном потоке?


 
Медвежонок Пятачок ©   (2009-02-02 12:54) [57]

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


 
Сергей М. ©   (2009-02-02 12:54) [58]


> Тимоха   (02.02.09 12:40) [54]


А зачем  потоку знать про какие-то формы и окна ?
Достаточно сказать ему, мол, на тебе первым параметром конструктора URL, делай свое дело, когда будешь готов отдать результат работы, вызови вот такой-то метод, который тебе передан, например, вторым параметром конструктора.


 
Тимоха   (2009-02-02 13:08) [59]

Почему пофиг, если процедур, которые должны параллельно парсить данные будет больше 1, то форма явно будет плохо откликаться пользователю. Значит скачиванием страниц будет заниматься один поток. А другие можно направить на анализ данных. Верно?

По поводу второго параметра конструктора, про метод. Не понял как это будет выглядеть.


 
Медвежонок Пятачок ©   (2009-02-02 13:11) [60]

Значит скачиванием страниц будет заниматься один поток.

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


 
Сергей М. ©   (2009-02-02 13:13) [61]


> Не понял как это будет выглядеть


Даже если не понял, то есть еще и событие TThread.OnTerminate - перед стартом потока назначь свой обработчик и в теле обработчика обращайся к объекту-потоку для считывания результатов его работы


 
Тимоха   (2009-02-02 13:48) [62]

Спасибо! А что должно выступать в роли буфера, через который будут добавляться данные в мэйн тред?


 
Медвежонок Пятачок ©   (2009-02-02 13:52) [63]

...
private
...
page: string;
....


 
Сергей М. ©   (2009-02-02 13:56) [64]


> что должно выступать в роли буфера


Например, свойства того самого объекта-потока


 
Anatoly Podgoretsky ©   (2009-02-02 14:54) [65]

> Тимоха  (02.02.2009 11:29:36)  [36]

Да ну, так и не приводят?


 
Тимоха   (2009-02-02 19:46) [66]

Основной поток:

procedure TForm1.btn1Click(Sender: TObject);
var
 potok: TTest;
begin
 potok := TTest.Create(true);
 potok.FreeOnTerminate := true;
 potok.Priority := tpNormal;
 potok.Main_handle := Form1.Handle;
 potok.Url := "http://www.delphimaster.ru/cgi-bin/forum.pl?n=18";
 potok.Resume;
end;

procedure TForm1.handlenewdata(var message: TMessage);
var
 data: PChar;
begin
 data := PChar(Pointer(message.LParam)^);
 lst1.Items.Add(data)
end;


Рабочий поток:

type
 TTest = class(TThread)
 private
   http: tidhttp;
   page: string;
   FMain_handle: THandle;
   FUrl: string;
   { Private declarations }
   constructor create;
 protected
   procedure Execute; override;
 public
   property Url: string write FUrl;
   property Main_handle: THandle write FMain_handle;
 end;

implementation

constructor TTest.Create;
begin
 inherited Create(True);
 FreeOnTerminate := True;
 Self.Priority := tpNormal;
 Resume;
end;

procedure TTest.Execute;
var
 index, count: Integer;
 s: PAnsiChar;
begin
 http := TIdHTTP.Create(nil);
 http.ProtocolVersion := pv1_1;
 page := http.Get(FUrl);
 count := 0;
 index := PosEx("<nobr>", page, count);
 repeat
   count := PosEx("
", page, index);
   GetMem(s, SizeOf(s));
   s := PChar(Copy(page, index + 9, count - index - 9));
   SendMessage(FMain_handle, wm_buf, 0, dword(@s));
   index := PosEx("<nobr>", page, count);
 until index = 0;
 http.Free;
end;


так нормально?


 
Palladin ©   (2009-02-02 19:54) [67]

бред. перепродумай. посмотри на конструктор потока (код конструктора выполняется в основном потоке), и посмотри что у тебя творится в btn1click. почувствуй бред )


 
Тимоха   (2009-02-02 20:41) [68]

constructor Create(h: THandle; Url: string); overload;

constructor TTest.Create(h: THandle; Url: string);
begin
 inherited Create(True);
 FUrl := url;
 hwnd := h;
 Self.Priority := tpNormal;
 Self.FreeOnTerminate := true;
 http := TIdHTTP.Create(nil);
 Resume; имеет разницу где выполнять поток, здесь или в мэйнтреде
end;

procedure TForm1.btn1Click(Sender: TObject);
var
 potok: TTest;
begin
 potok := TTest.create(form1.Handle, "http://www.delphimaster.ru/cgi-bin/forum.pl?n=18");
end;


 
Anatoly Podgoretsky ©   (2009-02-02 21:29) [69]

> Тимоха  (02.02.2009 20:41:08)  [68]

А у тебя где выполняется


 
Тимоха   (2009-02-02 21:30) [70]

сейчас в create потока.


 
Сергей М. ©   (2009-02-02 21:55) [71]


> Тимоха   (02.02.09 20:41) [68]


> Self.Priority := tpNormal;
>  Self.FreeOnTerminate := true;


Опять "забыл" ?
теперь-то откуда скопировал ?)


 
Anatoly Podgoretsky ©   (2009-02-02 23:18) [72]

> Тимоха  (02.02.2009 21:30:10)  [70]

create выполняется в основном потоке.


 
Тимоха   (2009-02-02 23:37) [73]

Когда тогда надо задавать приоритет? и выставлять freeonterminate?


 
Eraser ©   (2009-02-02 23:44) [74]

> [73] Тимоха   (02.02.09 23:37)
> Когда тогда надо задавать приоритет?

в начале OnExecute.

> и выставлять freeonterminate?

где угодно, можно там же.


 
Тимоха   (2009-02-02 23:48) [75]

если я правильно понял:

procedure TTest.Execute;
begin
 Self.Priority := tpNormal;
 Self.FreeOnTerminate := true;
...

end;


Но почему именно так?


 
Eraser ©   (2009-02-02 23:52) [76]

> [75] Тимоха   (02.02.09 23:48)

можно и не так, можно и из вне, так понятнее.


 
Тимоха   (2009-02-03 00:01) [77]

мне не понятно почему неправильно держать эти строки в конструкторе потока?


 
Eraser ©   (2009-02-03 00:22) [78]

> [77] Тимоха   (03.02.09 00:01)

можно, только после inherited.


 
Riply ©   (2009-02-03 00:51) [79]

> [73] Тимоха   (02.02.09 23:37)
> Когда тогда надо задавать приоритет? и выставлять freeonterminate?

Да мне кажется, что Сергей М. в [71] инересовался присхождением Self. :)

P.S.
А ты молодец.
При прочтении данной ветки, складывается такое впечатление, что все у тебя получится.
(Рано или поздно :) )


 
Тимоха   (2009-02-03 00:58) [80]

Спасибо! что плохого в Self?


 
Тимоха   (2009-02-03 01:01) [81]

вмысле без него))))))))


 
Тимоха   (2009-02-03 05:25) [82]

Передаю record через указатель.
 try
   mess := PRecord(message.LParam);
   mmo1.lines.Add("Имя: " + mess.name + ", Тема: " + mess.tema);
 finally
   Dispose(mess);
 end;


Результат:

Имя: koha!, Тема: Вопрос по функции API Openfile()
Имя: Тимоха, Тема: Организация работы потоков
Имя: mr.devil, Тема: Задание кодировки для xml
Имя: CodeMaster, Тема: Отключение скроллбаров
Имя: killaTank, Тема: Создание базы (Db) с помошью Delphi
Имя: cruiser, Тема: WinInet и закачка файла из Интернет через прокси с авторизацией.


 
Тимоха   (2009-02-03 06:27) [83]

Возникли вопросы по поводу памяти,

 repeat
   New(mess); // выделяю память
   count_name := PosEx("", page, index_name);
   count_tema := PosEx("</a>", page, index_tema);
   mess.tema := Copy(page, index_tema + 7, count_tema - index_tema - 7);
   mess.name := Copy(page, index_name + 9, count_name - index_name - 9);
   SendMessage(hwnd, wm_buf, 0, Integer(mess));
   index_name := PosEx("<nobr>", page, count_name);
   index_tema := PosEx("&n=18">", page, count_tema);
 until index_name = 0;

try
  mess := PRecord(message.LParam);
  mmo1.lines.Add("Имя: " + mess.name + ", Тема: " + mess.tema);
finally
  Dispose(mess);  удаляю
end;


верно ли будет такая реализация с памятью?


 
Сергей М. ©   (2009-02-03 08:18) [84]


> что плохого в Self?


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


> верно ли будет такая реализация с памятью?
>


Где, в каком месте кода все это происходит ?


 
Сергей М. ©   (2009-02-03 08:24) [85]

И чем не устраивает вариант с обработкой OnTerminate ?


 
Тимоха   (2009-02-03 19:57) [86]

Это в execute рабочего треда:

repeat
  New(mess); // выделяю память
  count_name := PosEx("", page, index_name);
  count_tema := PosEx("</a>", page, index_tema);
  mess.tema := Copy(page, index_tema + 7, count_tema - index_tema - 7);
  mess.name := Copy(page, index_name + 9, count_name - index_name - 9);
  SendMessage(hwnd, wm_buf, 0, Integer(mess));
  index_name := PosEx("<nobr>", page, count_name);
  index_tema := PosEx("&n=18">", page, count_tema);
until index_name = 0;


Это в мэйнтреде:
try
 mess := PRecord(message.LParam);
 mmo1.lines.Add("Имя: " + mess.name + ", Тема: " + mess.tema);
finally
 Dispose(mess);  удаляю
end;


 
Сергей М. ©   (2009-02-03 20:12) [87]


> Тимоха   (03.02.09 19:57) [86]


Что ты как попугай заладил одно и то же ?)

На [85] ответь)..


 
Тимоха   (2009-02-03 20:14) [88]

Меня все устраивает, я хочу сделать оба варианта. И понять какой лучше.


 
Сергей М. ©   (2009-02-03 20:23) [89]

Ясно)


 
Тимоха   (2009-02-03 20:32) [90]

Для OnTerminate:
делаю  

...
procedure HandleOnTerminate(Sender:TObject);
...

MyThread:= TTest.create("http://www.delphimaster.ru/cgi-bin/forum.pl?n=18");
MyThread.OnTerminate := HandleOnTerminate;

Не понимаю как будут передаваться данные в этом случае? Как поток отработает, наступает OnTerminate, тут то мы и должны данные где то хранить (в буфере?), вытаскиваем из буфера и все тип-топ. Так должен выглядеть алгоритм?


 
Медвежонок Пятачок ©   (2009-02-03 20:46) [91]

в онтерминате обработчике нитка еше жива.
и живы свойства нитки


 
Тимоха   (2009-02-03 20:50) [92]

Спасибо!
Т.е. в рабочем треде нужно создать property в него записывать данные

а при onterminate
в procedure HandleOnTerminate(Sender:TObject);

обращаться к потоку к заданному property и вытаскивать оттуда данные?


 
Тимоха   (2009-02-03 21:43) [93]

Сделал так:
В рабочем треде создаю TList,List_count.

   try
     New(mess);
     List.Add(mess);
     Inc(List_count);
     mess.tema := Copy(page, index_tema + 7, count_tema - index_tema - 7);
     mess.name := Copy(page, index_name + 9, count_name - index_name - 9);
   finally
   end;


в HandleOnTerminate в мэйнтреде:

 try
   for i := 0 to potok.List_count - 1 do
   begin
     mess := potok.List.Items[i];
     mmo1.Lines.Add("Имя: " + mess.name + ", Тема: " + mess.tema);
   end;
 finally
   Dispose(mess);
 end;


При таком варианте утечки памяти не будет?


 
Тимоха   (2009-02-04 00:26) [94]

Объясните пожалуйста что использовать лучше и почему? sendmessage или onterminate для получения данных с треда?


 
Медвежонок Пятачок ©   (2009-02-04 00:41) [95]

это вопрос мировоззрения и вкуса


 
Eraser ©   (2009-02-04 01:00) [96]

> [93] Тимоха   (03.02.09 21:43)


> При таком варианте утечки памяти не будет?

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

  New(mess);
  try
    // send message
  finally
    Dispose(mess);
  end;

предпочтительный:
выделять память для сообщения в стеке.


 
Тимоха   (2009-02-04 01:01) [97]

А если рассматривать с точки зрения что потом я собираюсь синхронизировать треды?


 
Eraser ©   (2009-02-04 01:04) [98]

> [94] Тимоха   (04.02.09 00:26)


> Объясните пожалуйста что использовать лучше и почему?

лучше почитать матчасть, вот что лучше. т.е. разобраться, что такое sendmessage и что такое onterminate. тогда и таких вопросов задавать не будешь.


 
Riply ©   (2009-02-04 01:21) [99]

> [93] Тимоха   (03.02.09 21:43)

Что-то я не поняла: ты сколько раз выделяешь память и сколько раз освобождаешь ?
И зачем введена переменная List_count ?


 
Тимоха   (2009-02-04 01:30) [100]

List_count не нужен. Облажался.


 
Тимоха   (2009-02-04 04:36) [101]

Тред собирает все имена авторов тем с форума (начинающим).
Теперь нужно чтобы он работал через каждые скажем 5 мин и проверял, если есть новые то добавляем в список, если нет то ниче не делаем.
Каков алгоритм?
Я представляю это себе так, есть таймер и есть булевая переменная, которая отвечает за то какой раз запустился тред. В таймере проверяем если поток уже запускался, то теперь через каждые 5 мин запускаем его снова. Ну и сделать какую то переменную, которая отвечала за то работает в данный момент поток или нет.


 
Riply ©   (2009-02-04 04:59) [102]

> [101] Тимоха   (04.02.09 04:36)
> Каков алгоритм?

Ты не ответил на мой первый вопрос в [99]


 
Тимоха   (2009-02-04 05:58) [103]


> Ты не ответил на мой первый вопрос в [99]

Выделяю и освобождаю ровно столько, сколько записей передаю


 
Сергей М. ©   (2009-02-04 09:15) [104]


> если рассматривать с точки зрения что потом я собираюсь
> синхронизировать треды?


И событие OnTerminate и синхронная отправка/получение оконного сообщения есть событие синхронизации.


 
Riply ©   (2009-02-04 10:18) [105]

> [103] Тимоха   (04.02.09 05:58)
> Выделяю и освобождаю ровно столько, сколько записей передаю

Конечно, сложно судить по вырванным кусочкам,
но из кода, приведенного, в [93] я не вижу этого.


 
Тимоха   (2009-02-04 11:12) [106]

procedure TForm1.btn1Click(Sender: TObject);
begin
 potok := TTest.create(form1.Handle, "http://www.delphimaster.ru/cgi-bin/forum.pl?n=18", wm_buf);
end;

procedure TForm1.handlenewdata(var message: TMessage);
var mess: PRecord;
begin
 try
   mess := Pointer(message.LParam);
   if listbox1.Items.IndexOf(mess^.name) = -1 then
   begin
     ListBox1.Items.Add(mess^.name);
   end;
   Dispose(mess);
 except
   ShowMessage("Error!");
 end;

end;

type
 PRecord = ^TRecord;
 TRecord = record
   name: string[50];
   tema: string[150];
 end;

type
 TTest = class(TThread)
 private
   http: tidhttp;
   page: string;
   FUrl: string;
   hwnd: THandle;
   FMsg: Integer;
 protected
   procedure Execute; override;
 public
   constructor Create(h: THandle; Url: string;aMsg:Integer); overload;
   destructor Destroy; override;
 end;

implementation

constructor TTest.Create(h: THandle; Url: string; aMsg:Integer);
begin
 inherited Create(True);
 FUrl := url;
 hwnd := h;
 FMsg := aMsg;
 http := TIdHTTP.Create(nil);
 Priority := tpNormal;
 FreeOnTerminate := true;
 Resume;
end;

destructor TTest.destroy;
begin
 http.Free;
 inherited;
end;

procedure TTest.Execute;
var
 index_name, count_name: Integer;
 index_tema, count_tema: Integer;
 mess: PRecord;
begin
 page := http.Get(FUrl);
 index_tema := 0;
 index_name := 0;
 count_name := 0;
 count_tema := 0;
 index_tema := PosEx("&n=18">", page, count_tema);
 index_name := PosEx("<nobr>", page, count_name);
 repeat
   count_name := PosEx("
", page, index_name);
   count_tema := PosEx("</a>", page, index_tema);
   try
     New(mess);
     mess^.tema := Copy(page, index_tema + 7, count_tema - index_tema - 7);
     mess^.name := Copy(page, index_name + 9, count_name - index_name - 9);
     PostMessage(hwnd, FMsg, 0, Integer(mess));
     Sleep(1);
   finally
   end;
   index_name := PosEx("<nobr>", page, count_name);
   index_tema := PosEx("&n=18">", page, count_tema);
 until index_name = 0;
end;


 
Тимоха   (2009-02-04 11:19) [107]

sleep не туда засунул


 
Сергей М. ©   (2009-02-04 11:23) [108]


> sleep не туда засунул


Оттого, видимо, и не выходит каменный цветок ?)
Причем здесь слип ? Кому он интересен кроме тебя ? Ты же о синхронизации сейчас печешься, а не о "тормозах"..


 
Тимоха   (2009-02-04 11:27) [109]

на мой [101] никто не ответил


 
Медвежонок Пятачок ©   (2009-02-04 11:30) [110]

В таймере проверяем если поток уже запускался, то теперь через каждые 5 мин запускаем его снова.

то есть ни один поток после старта программы не будет запущен никогда.


 
Тимоха   (2009-02-04 11:31) [111]

почему же, нажимаем на кнопку и пошел.


 
Сергей М. ©   (2009-02-04 11:35) [112]


> Тимоха   (04.02.09 11:27) [109]


Так.
И что с чем синхронизировать при этом надо ?


 
Медвежонок Пятачок ©   (2009-02-04 11:35) [113]

таймер здесь плохой помощник.

допустим, что за секунду до его тика очередной поток завершился, и выставил флаг "я уже запускался".
и не успел он как следует передохнуть, как таймер пошлет его на делфимастер снова.


 
Тимоха   (2009-02-04 11:44) [114]

Сергей М, допустим будет еще один поток, который будет делать тоже самое что и первый, но только с другой конференции и проверять есть ли там вопросы какого нить автора из 20-ки с конференции для начинающих, есть есть, то в листбоксе он должен как то отметится. А первый в это время проверяет появились ли новые и добавляет их в список, если из 20-ки автор выбыл, то его из списка удаляем даже если он есть в другой конференции. Типо того.
Медвежонок Пятачок, как решить?


 
Медвежонок Пятачок ©   (2009-02-04 11:47) [115]

поток при завершении должен либо сам записать в структуру, ассоциированную с его конференцией время следующего старта, либо за него это должен сделать главный поток (Now + Delta).
В таймере смотреть, не превышет ли текущее время время следующего запуска очередного потока. Если превышает, то стартовать.
Булеву переменную убрать.


 
Тимоха   (2009-02-05 03:42) [116]

Спасибо! Вот код двух юнитов, взгляните пожалуйста и скажите что конкретно в коде не правильно:
Следующие разы поток не запускается, мне кажется что он неправильно освобождается.
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, ExtCtrls;

const
 wm_buf = wm_app + 1234;

type
 TForm1 = class(TForm)
   btn1: TButton;
   ListBox1: TListBox;
   ListBox2: TListBox;
   Timer1: TTimer;
   Button1: TButton;
   procedure btn1Click(Sender: TObject);
   procedure Timer1Timer(Sender: TObject);
   procedure FormCreate(Sender: TObject);
 private
   procedure handleonterminate(sender: TObject);
   procedure handlenewdata(var message: TMessage); message wm_buf;
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;
 Time_end, delta: TDateTime;
implementation

uses Unit2;

{$R *.dfm}
var
 potok: TTest;

procedure TForm1.btn1Click(Sender: TObject);
begin
 potok := TTest.create(form1.Handle, "http://www.delphimaster.ru/cgi-bin/forum.pl?n=18", wm_buf);
 potok.OnTerminate := handleonterminate;
end;

procedure TForm1.handlenewdata(var message: TMessage);
var mess: PRecord;
begin
 try
   mess := Pointer(message.LParam);
   if listbox1.Items.IndexOf(mess^.name) = -1 then
     ListBox1.Items.Add(mess^.name);
   Dispose(mess);
 except
   //
 end;

end;

procedure TForm1.handleonterminate(sender: TObject);
begin
 Time_end := Now + Delta;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 if Time_end <> 0 then
   if (Now >= Time_end) and not Assigned(potok) then
     potok := TTest.create(form1.Handle, "http://www.delphimaster.ru/cgi-bin/forum.pl?n=18", wm_buf);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 Time_end := StrToTime("00:00:00");
 delta := StrToTime("00:00:05");
end;

end.

unit Unit2;

interface

uses
 Classes, idhttp, unit1, StrUtils, windows, SysUtils;

type
 PRecord = ^TRecord;
 TRecord = record
   name: string[50];
   tema: string[150];
 end;

type
 TTest = class(TThread)
 private
   http: tidhttp;
   page: string;
   FUrl: string;
   hwnd: THandle;
   FMsg: Integer;
 protected
   procedure Execute; override;
   procedure PostRecord(Rec:PRecord);
 public
   constructor Create(h: THandle; Url: string;aMsg:Integer); overload;
   destructor Destroy; override;
 end;

implementation

constructor TTest.Create(h: THandle; Url: string; aMsg:Integer);
begin
 inherited Create(True);
 FUrl := url;
 hwnd := h;
 FMsg := aMsg;
 http := TIdHTTP.Create(nil);
 Priority := tpNormal;
 FreeOnTerminate := True;
 Resume;
end;

destructor TTest.destroy;
begin
 http.Free;
 inherited;
end;

procedure TTest.Execute;
var
 index_name, count_name: Integer;
 index_tema, count_tema: Integer;
 mess: PRecord;
begin
 page := http.Get(FUrl);
 index_tema := 0;
 index_name := 0;
 count_name := 0;
 count_tema := 0;
 index_tema := PosEx("&n=18">", page, count_tema);
 index_name := PosEx("<nobr>", page, count_name);
 repeat
   count_name := PosEx("
", page, index_name);
   count_tema := PosEx("</a>", page, index_tema);
   try
     Sleep(1);
     New(mess);
     mess^.tema := Copy(page, index_tema + 7, count_tema - index_tema - 7);
     mess^.name := Copy(page, index_name + 9, count_name - index_name - 9);
     PostRecord(mess);
   finally
   end;
   index_name := PosEx("<nobr>", page, count_name);
   index_tema := PosEx("&n=18">", page, count_tema);
 until index_name = 0;
end;

procedure TTest.PostRecord(Rec: PRecord);
begin
 PostMessage(hwnd, FMsg, 0, Integer(Rec));
end;

end.


 
Тимоха   (2009-02-05 11:50) [117]

Допустим у меня поток не прекращает работу на протяжении работы все программы, и завершается при application.terminate
Если я добавлю еще один поток, который будет тоже посылать сообщение, а на форме будет обрабатывать и обращаться к listbox. В таком случае не будет некорректных данных?



Страницы: 1 2 3 вся ветка

Форум: "Начинающим";
Текущий архив: 2009.03.29;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.78 MB
Время: 0.052 c
2-1233804054
snake-as
2009-02-05 06:20
2009.03.29
При открытии файла через OpenDialog имя файла не сохраняется


2-1234033046
Pavel
2009-02-07 21:57
2009.03.29
Суммирование времени


15-1233297032
Phenix
2009-01-30 09:30
2009.03.29
Help!!!


15-1232373798
TCrash
2009-01-19 17:03
2009.03.29
.bat скопировать ОДИН файл


15-1232753631
trsteep
2009-01-24 02:33
2009.03.29
Модель базы данных.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский