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

Вниз

Вопрос по потокам   Найти похожие ветки 

 
leonidus   (2004-07-04 00:09) [0]

Есть код:

type
  TThread1 = class(TThread)
  private
    { Private declarations }
  protected
    procedure DoWork;
    procedure Execute; override;
  public
   URL: string;
  end;

  TThread2 = class(TThread)
  private
    { Private declarations }
  protected
    procedure DoWork;
    procedure Execute; override;
  public
   URL: string;
  end;

.....
.....

procedure TThread1.Execute;
begin
 Synchronize(DoWork);
end;

procedure TThread2.Execute;
begin
 Synchronize(DoWork);
end;

procedure TThread1.DoWork;
begin
 form1.HTTP1.Get(t1.url,"c:\1.txt");
end;

procedure TThread1.DoWork;
begin
 form1.HTTP2.Get(t2.url,"c:\2.txt");
end;

по клику на кнопке запускаю потоки

var
 t1:TThread1;
 t2:TThread2;
...
...
t1 := TThread1.Create(true);
t1.URL := turn[i];
t1.Resume;
t2 := TThread2.Create(true);
t2.URL := turn[i];
t2.Resume;
.....

в результате потоки качают не параллельно а один за другим, т.е. сначала первый потом второй. Что я делаю не так? И еще вопрос, как корректно убить поток, если закачка еще идет, t1.Terminate; выдает run-time error?


 
jack128 ©   (2004-07-04 00:59) [1]


> procedure TThread1.Execute;
> begin
>  Synchronize(DoWork);
> end;
>
> procedure TThread2.Execute;
> begin
>  Synchronize(DoWork);
> end;
Архангельского читал? Убить этого гада надо..

Во первых убери синхроонизацию. А во вторых HTTP1 и HTTP2 создавай динамически в DoWork. И почитай какую нить нормальную книжку/статью, а не этого идиота..


 
TUser ©   (2004-07-04 05:47) [2]

У тебя запускается T1, вызывается DoWork, а вызывается он в контексте основного потока, который соответственно не успевает запустить T2.


 
Григорьев Антон ©   (2004-07-04 07:05) [3]

http://www.delphikingdom.com/asp/answer.asp?IDAnswer=23480 - там похожая проблема обсуждалась.


 
leonidus   (2004-07-04 11:18) [4]

Дело в том, что синхронизация нужна для того, что бы срабатывали события компонентов HTTP1 и HTTP2 которые по ходу закачки в ProgressBar отображают ход работы. Может тогда синхронизацию в ругом месте поставить, подскажите пожалуста как это должно выглядеть. HTTP1 и HTTP2 создавать динамически неудобно, просто по тому, что в поставленной задаче будет 15 таких потоков, а у каждого HTTP1 несколько обработчиков событий. Или я неправ?


 
jack128 ©   (2004-07-04 11:54) [5]

Ссылку Антона прочитал? Он там весьма подробно разъяснил, что к чему..

В твоем конкретном случаи, я бы вообще cвою реализацию синхронизации:

procedure TThread1.Execute;
var
 _http: THttp; // нечего не знаю про этот класс, поэтому все методы и события условны..
begin
 _http := THttp.Create(nil);
 try
   _http.OnProgress := HttpProgressHandler;
   _http.SameMethod;
   _http.OtherMethod;
 finally
   _http.Free;
 end;
end;

procedure TThread1.HttpProgressHandler(Sender: TObject; Progress, Max: Integer);
begin
// тут возможны три варианта
// 1) Более торомзнутый
 Synchronize(UpdateProgressBar); // UpdateProgressBar - процедура в которой обновляешь состояние прогресбара
// 2) Глючный :-) Но вероятность глюка весьма низка
 with Form1.ProgressBar1 do
 begin
   PostMessage(Handle, PBM_SETRANGE, 0, MakeLong(0, Max)); // при вычислении свойства Handle возможны проблемы, если хенд прогресс бара еще не создан. Тогда он одновременно быдет создоваться из двух потоков...
   PostMessage(Handle, PBM_SETPOS, Progress, 0)
 end;
 // третий вариант - безглючная реализация второго
 PostMessage(ThreadWnd, MM_UPDATEPROGRESSBAR, Integer(Form1.ProgresBar1)MakeLong(Progress, Max)); // что такое THreadWnd - cм ниже..
end;

// необходимо для работы  третьего варианта..

var
 ThreadWnd: THandle = 0;
constructor TThread1.Create(...);
begin
 if ThreadWnd = 0 then
   THreadWnd := AllocateHWnd(ThreadWndProc);
 inherited (...);
end;

procedure TThread1.ThreadWndProc(var Message: TMessage);
begin
 if Message.Msg <> MM_UPDATEPROGRESSBAR then Exit;
 if Message.WParam <> 0 then
 with TProgressBar(Message.WParam) do
 begin
   Max := Message.lParam shr 16;
   Progress := Word(Message.lParam);
 end;
end;

finalization
 if ThreadWnd <> 0 then
   DeallocateHWnd(FThreadWnd);
end.


 
leonidus   (2004-07-04 13:42) [6]

Допусти такой вариант:

procedure TThread1.Execute;
var
_http: THttp;
begin
_http := THttp.Create(nil);
try
  _http.OnProgress := HttpProgressHandler;
  _http.SameMethod;
  _http.OtherMethod;
finally
  _http.Free;
end;
end;

procedure TThread1.HttpProgressHandler(Sender: TObject; Progress, Max: Integer);
begin
Synchronize(UpdateProgressBar);
end;

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

type
 TThread1 = class(TThread)
 private
   { Private declarations }
 protected
   procedure DoWork;
 public
  URL: string;
 end;

.....
.....

procedure TThread1.Execute;
begin
Synchronize(tform1.HTTP1.OnWork);
form1.HTTP1.Get(t1.url,"c:\1.txt");
end;

procdure tform1.HTTP1.OnWork(count:integer);
begin
ProgressBar.Position:=count;
//т.е. я предполагаю, что в потоке происходит закачка, соотв.
  компонент HTTP1 генеригует событие OnWork в котором и      
  происходит от прорисовка ProgressBar`а.
end;

по клику на кнопке запускаю потоки

var
t1:TThread1;
...
...
t1 := TThread1.Create(true);
t1.URL := turn[i];
t1.Resume;

//запускаю второй поток
.....


 
jack128 ©   (2004-07-04 14:14) [7]


> но во-первых я же говорю, класс _http создавать не надо
> он уже создан просто по умолчанию потому что компонент лежит
> на форме и все события будут "сниматься" именно с компонента
Ты не понял. Не всегда возможно создовать компонент в одном потоке, а использовать его в другом потоке. ВОЗМОЖНО с твоим THTTP такое прокатит, а может и нет. Я по этому поводу сказать нечего не могу, поскольку не работал с этим компонентом.

> Synchronize(tform1.HTTP1.OnWork);


> procdure tform1.HTTP1.OnWork(count:integer);
- даже не скомпилируется..


 
KSergey ©   (2004-07-04 14:40) [8]

>  [6] leonidus   (04.07.04 13:42)
> но во-первых я же говорю, класс _http создавать не надо
> он уже создан просто по умолчанию потому что компонент лежит
> на форме

Если вы собираетесь повзрослеть и таки работать с потоками грамотно - придется, увы, от этого удобства отказываться. [7] jack128 ©   (04.07.04 14:14) пишет почему.

2 [5] jack128 ©   (04.07.04 11:54)

Я так и не понял в чем отличие вротого варианта от третьего. Вернее, в каком случае могут возникнуть проблемы во втором случае? Все равно прогресс бар получит сообщения синхронно со своим родным, т.е. основным потоком (PostMessage, однако). В третьем же варианте используется просто окно-прослойка, но зачем? Какая разница? Тем более, что оно сознается вообще в рамках не основного потока!!

Я всегда просто слал свое сообщение той форме, на которой лежит прогресс бар (через Post), и уже в его обработчике выставлял свойства прогрессбара (из параметров сообщения). Где тут проблемы? И уж тем более не понятно зачем городить еще одно окно-прослойку...
Поясните для меня, плиз.


 
jack128 ©   (2004-07-04 16:09) [9]


> в каком случае могут возникнуть проблемы во втором случае?
>

все достаточно просто

function TWinControl.GetHandle: HWnd;
begin
 HandleNeeded;
 Result := FHandle;
end;

procedure TWinControl.HandleNeeded;
begin
 if FHandle = 0 then
 begin
   if Parent <> nil then Parent.HandleNeeded;
   CreateHandle;
 end;
end;

Предположем что на момент вызова PostMessage(ProgressBar1.Handle, ...) из дополнительного потока хендл прогрессбара еще не создан, тогда этот хендл будет создан в конетексте ДОПОЛНИТЕЛЬНОГО потока, в этом левом потоке даже цикла обработки сообщений нет. Или например СreateHandle вызывается одновременно из потока VCL и из дополнительного потока. Чему будет равно FHandle после таких вызовов? В любом слчае одно окно мы потеряем..

> Я всегда просто слал свое сообщение той форме, на которой
> лежит прогресс бар (через Post),
ну и не каких проблем ты не имел, я так понимаю? Вполне возможно, я же писал что вероятность ошибки во втором варианте весьма низка. Если ты не играешь, например с BorderStyle (а при изменении этого свойства окно пересоздается), то и вовсе стремиться к нулю..  
В любом случае гарантию дает только третий (ну и первый разумеется) вариант.


 
jack128 ©   (2004-07-04 16:13) [10]


> KSergey ©  

<off>
перерегистрируйся..
</off>


 
KSergey ©   (2004-07-04 20:00) [11]

> jack128 ©   (04.07.04 16:09) [9]

Признателен, очень ценные уточнения.
Ну на счет еще не создан - ну обычно поток после, ну на крайний случай - в конструкторе формы создаю.
А вот про то, что окно иногда пересоздается - это я забываю, факт. Это действительно аккуратно надо (благо, обычно не меняю свойства в run-time, которые приводят к пересозданию, но помнить конечно надо; глюков тут огребешь не мерянно, факт...).


 
leonidus   (2004-07-05 13:40) [12]

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


 
panov ©   (2004-07-05 14:09) [13]

>leonidus   (05.07.04 13:40) [12]

Твой код неправилен идеологически.
Задай вопрос в форуме "Сети".



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

Текущий архив: 2004.07.18;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.023 c
1-1088678430
Akella
2004-07-01 14:40
2004.07.18
Обработка событий различных объектов одной процедурой


1-1088693556
Agent[007]
2004-07-01 18:52
2004.07.18
Циклы...


11-1076769216
RA
2004-02-14 17:33
2004.07.18
Меня часто вспрашивают: "А зачем оно надо?".


3-1087982537
чайник1
2004-06-23 13:22
2004.07.18
Фильтр по симв.полю


1-1088933384
rolex
2004-07-04 13:29
2004.07.18
Как изменить цвет выделения (синий) в Listbox e на другой?