Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Организация работы потоков


Страницы:   1 2 3 4 5 6

Тимоха ©   (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. тогда и таких вопросов задавать не будешь.


Страницы:   1 2 3 4 5 6

Наверх

Титульная страница Поиск, карта сайта Написать письмо