![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Организация работы потоков
Тимоха © (2009-02-02 08:20:00)Написал программу, которая выполняет ряд некоторых функций.
Одни из которых это - связь с сайтом и получение от него определенной информации, анализ полученной информации, проверка наличия новых данных на том же сайте и их загрузка.
Необходимо реализовать работу функций программы с использованием потоков.
Более подробное описание задачи потоков:
При старте программы возможны два варианта:
(А).Программа запускается впервые,поэтому запускается поток ThrStartFirst. Этот поток скачивает с сайта страницу, парсит нужные данные и добавляет их в более расширенный компонент listbox(у листбокса есть свойства text,text1,text2,text3). В то время как работает ThrStartFirst, запускается следующий поток ThrStratAnalys, который берет по очереди каждый итем листбокса, вытаскивает свойство text и скачивает страницу с интернета, уже анализируя полученные данные и сохраняя в определенной структуре в файл.В это же время должен работать еще один поток ThrUpdate. Он скачивает всю туже страницу и наблюдает за появлением новых данных,удалением тех которые уже удалены с той страницы в интернете, и изменением каких то данных.( запускаться поток должен через определенное заданное время)
Вариант (В). Программа запущенна не впервые. В листбокс заносятся данные из сохраненных файлов(учитывая что вариант А полностью отработал в предыдущей загрузке, если нет то скачиваются файлы, которые не были скачаны в пером запуске А). Как только данные занесены, а это происходит весьма быстро так как файлы находяятся на диске в формате txt, то запускается поток ThrUpdate, выполняет те же операции что и в варианте А. Идеально было, если б таких ThrUpdate было больше одного(т.е.ThrUpdate1,2,3,4... которые выполняли свои функции с данными, не обязательно изменявшие данные в листбоксе).
Изучал работу критических секций,мьютексов, семафоров и других вариантов синхронизации. Но понять пока еще трудно. Надеюсь на помощь в создании алгоритмов. Надеюсь услышать советы: что лучше использовать в моем случае, на что обратить внимание.
P.S. Программа будет работать с моим сайтом. Для скачивания содержимого страниц используется idhttp.
Заранее благодарен.
Тимоха (2009-02-05 11:50:00) [1]Допустим у меня поток не прекращает работу на протяжении работы все программы, и завершается при application.terminate
Если я добавлю еще один поток, который будет тоже посылать сообщение, а на форме будет обрабатывать и обращаться к listbox. В таком случае не будет некорректных данных?
Тимоха (2009-02-05 03:42:00) [2]Спасибо! Вот код двух юнитов, взгляните пожалуйста и скажите что конкретно в коде не правильно:
Следующие разы поток не запускается, мне кажется что он неправильно освобождается.
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(' ', page, count_name);
repeat
count_name := PosEx('', page, index_name);
count_tema := PosEx('', 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(' ', 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-04 11:47:00) [3]поток при завершении должен либо сам записать в структуру, ассоциированную с его конференцией время следующего старта, либо за него это должен сделать главный поток (Now + Delta).
В таймере смотреть, не превышет ли текущее время время следующего запуска очередного потока. Если превышает, то стартовать.
Булеву переменную убрать.
Тимоха (2009-02-04 11:44:00) [4]Сергей М, допустим будет еще один поток, который будет делать тоже самое что и первый, но только с другой конференции и проверять есть ли там вопросы какого нить автора из 20-ки с конференции для начинающих, есть есть, то в листбоксе он должен как то отметится. А первый в это время проверяет появились ли новые и добавляет их в список, если из 20-ки автор выбыл, то его из списка удаляем даже если он есть в другой конференции. Типо того.
Медвежонок Пятачок, как решить?
Сергей М. (2009-02-04 11:35:00) [5]
> Тимоха (04.02.09 11:27) [109]
Так.
И что с чем синхронизировать при этом надо ?
Медвежонок Пятачок (2009-02-04 11:35:00) [6]таймер здесь плохой помощник.
допустим, что за секунду до его тика очередной поток завершился, и выставил флаг "я уже запускался".
и не успел он как следует передохнуть, как таймер пошлет его на делфимастер снова.
Тимоха (2009-02-04 11:31:00) [7]почему же, нажимаем на кнопку и пошел.
Медвежонок Пятачок (2009-02-04 11:30:00) [8]В таймере проверяем если поток уже запускался, то теперь через каждые 5 мин запускаем его снова.
то есть ни один поток после старта программы не будет запущен никогда.
Тимоха (2009-02-04 11:27:00) [9]на мой [101] никто не ответил
Сергей М. (2009-02-04 11:23:00) [10]
> sleep не туда засунул
Оттого, видимо, и не выходит каменный цветок ?)
Причем здесь слип ? Кому он интересен кроме тебя ? Ты же о синхронизации сейчас печешься, а не о "тормозах"..
Тимоха (2009-02-04 11:19:00) [11]sleep не туда засунул
Тимоха (2009-02-04 11:12:00) [12]
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(' ', page, count_name);
repeat
count_name := PosEx('', page, index_name);
count_tema := PosEx('', 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(' ', page, count_name);
index_tema := PosEx('&n=18">', page, count_tema);
until index_name = 0;
end;
Riply (2009-02-04 10:18:00) [13]> [103] Тимоха (04.02.09 05:58)
> Выделяю и освобождаю ровно столько, сколько записей передаю
Конечно, сложно судить по вырванным кусочкам,
но из кода, приведенного, в [93] я не вижу этого.
Сергей М. (2009-02-04 09:15:00) [14]
> если рассматривать с точки зрения что потом я собираюсь
> синхронизировать треды?
И событие OnTerminate и синхронная отправка/получение оконного сообщения есть событие синхронизации.
Тимоха (2009-02-04 05:58:00) [15]
> Ты не ответил на мой первый вопрос в [99]
Выделяю и освобождаю ровно столько, сколько записей передаю
Riply (2009-02-04 04:59:00) [16]> [101] Тимоха (04.02.09 04:36)
> Каков алгоритм?
Ты не ответил на мой первый вопрос в [99]
Тимоха (2009-02-04 04:36:00) [17]Тред собирает все имена авторов тем с форума (начинающим).
Теперь нужно чтобы он работал через каждые скажем 5 мин и проверял, если есть новые то добавляем в список, если нет то ниче не делаем.
Каков алгоритм?
Я представляю это себе так, есть таймер и есть булевая переменная, которая отвечает за то какой раз запустился тред. В таймере проверяем если поток уже запускался, то теперь через каждые 5 мин запускаем его снова. Ну и сделать какую то переменную, которая отвечала за то работает в данный момент поток или нет.
Тимоха (2009-02-04 01:30:00) [18]List_count не нужен. Облажался.
Riply (2009-02-04 01:21:00) [19]> [93] Тимоха (03.02.09 21:43)
Что-то я не поняла: ты сколько раз выделяешь память и сколько раз освобождаешь ?
И зачем введена переменная List_count ?
Eraser (2009-02-04 01:04:00) [20]> [94] Тимоха (04.02.09 00:26)
> Объясните пожалуйста что использовать лучше и почему?
лучше почитать матчасть, вот что лучше. т.е. разобраться, что такое sendmessage и что такое onterminate. тогда и таких вопросов задавать не будешь.