Текущий архив: 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.5 MB
Время: 0.022 c