Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.03.29;
Скачать: CL | DM;

Вниз

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

 
Тимоха   (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;
Скачать: CL | DM;

Наверх




Память: 0.79 MB
Время: 0.032 c
1-1208173651
denmin
2008-04-14 15:47
2009.03.29
Как обратится к компоненту созданному через TCustomControl


1-1208942275
carmen
2008-04-23 13:17
2009.03.29
эксторт в XML из ExpressQuantumGrid Suite 6.24


15-1232620643
Alkid
2009-01-22 13:37
2009.03.29
Исследование мыслительных процессов программистов


15-1232851838
Vjik
2009-01-25 05:50
2009.03.29
Очень важные сообщения


6-1201453017
XakeP
2008-01-27 19:56
2009.03.29
Как написать прокси-сервер