Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.07.18;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.047 c
3-1087769417
Newb
2004-06-21 02:10
2004.07.18
Проблема с DBCheckBox


1-1088599073
romeo
2004-06-30 16:37
2004.07.18
Творится какая-то странная хренотень с записью строки в поток.


3-1087818490
SerGja
2004-06-21 15:48
2004.07.18
Кол-во записей после запроса ?


3-1087994111
Николай
2004-06-23 16:35
2004.07.18
Сохранение изменений


14-1088102829
Knight
2004-06-24 22:47
2004.07.18
Моторола C350... что, правда, брать не стоит?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский