Форум: "Начинающим";
Текущий архив: 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.619 c