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

Вниз

TThread   Найти похожие ветки 

 
CanBlow   (2003-07-28 18:27) [0]

Я хочу вынести увеличение ProgressBar.Position в отдельный TThread, но не могу сделать переменную доступную из потока. Делал так, но ничего не получается.
unit ThreadPB;

interface

uses
Classes, ComCtrls,Graphics, ExtCtrls;

type
TThreadPB = class(TThread)
private
FProgressBar : TProgressBar;
FI : Integer;
protected
procedure Execute; override;
public
constructor Create( ProgressBar : TProgressBar; I : Integer);

end;
implementation



constructor TThreadPB.Create( ProgressBar : TProgressBar; I : Integer);
begin
FProgressBar := ProgressBar;
FI:=I;
FreeOnTerminate := True;
inherited Create(False);
end;


procedure TThreadPB.Execute;
begin
while true do FProgressBar.Position:=FI;
end;

end.

Если надо, то могу подробнее


 
jack128   (2003-07-28 18:34) [1]

Во первых для обращения к компонентом VCL нужно использовать TThread.Synchronize()
во вторых выносить только обновление прогресс бара в поток это бред.. Выноси сюда (в поток) свой длительный процесс и переодичски обновляй прогресбар..


 
CanBlow   (2003-07-28 18:43) [2]

Допустим ProgressBar обновляется так :
for I:=1 to 10000 do ProgressBar1.position:=I;
Согласитесь, это несколько тормозит процесс выполнения длительной задачи, например

ProgressBar1.Max:=10000;
For I:=1 to 10000 do
begin
DoSomeThing;
ProgressBar1.Position:=I;
end;

Это только пример.
Так вот, я хочу выполнять операцию в главном Thread и сделать так, чтобы второй Thread параллельно следил за I и периодически обновлял ProgressBar. Надеюсь я понятно объяснил :)


 
Толик   (2003-07-28 18:48) [3]

Из потока достаточно посылать сообщения об обновлении для ProgressBar"а через PostMessage. И потом, ведь не обязательно его обновлять через каждый проход цикла, а делать это каждый десятый или сотый раз.


 
CanBlow   (2003-07-28 19:00) [4]

На счёт PostMessage посмотрю...
А, вообще, я вот как делал.
И скажите : при таком способе, как у меня, TThreadPB, вообще, видит, что I меняется?

Вызываю так
procedure TForm1.Button1Click(Sender: TObject);
var
I : Integer;
begin
ProgressBar1.Max:=100000;
TThreadPB.Create(ProgressBar1, I);
for I:=1 to 100000 do Sleep(10);
end;

end.

Код потока
unit ThreadPB;

interface

uses
Classes, ComCtrls,Graphics, ExtCtrls;

type
TThreadPB = class(TThread)
private
FProgressBar : TProgressBar;
FI : Integer;
protected
procedure Execute; override;
Procedure PBDo;
public
constructor Create( ProgressBar : TProgressBar; I : Integer);

end;

implementation



constructor TThreadPB.Create( ProgressBar : TProgressBar; I : Integer);
begin
FProgressBar := ProgressBar;
FI:=I;
FreeOnTerminate := True;
inherited Create(False);
end;

procedure TThreadPb.PBDo;
begin
while true do FProgressBar.Position:=FI;
end;

procedure TThreadPB.Execute;
begin
Synchronize(PBDo);
end;

end.

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

> Толик

А можно ли всё-таки через Position? Ведь в отдельном потоке он всё равно тормозить не должен?


 
NickBat   (2003-07-28 19:04) [5]

> Так вот, я хочу выполнять операцию в главном Thread и сделать > так, чтобы второй Thread параллельно следил за I и
> периодически обновлял ProgressBar. Надеюсь я понятно
> объяснил :)

Зачем для обновления ProgressBar заводить отдельный поток?

- Это бред (С) jack128 © (28.07.03 18:34)


 
CanBlow   (2003-07-28 19:13) [6]

А как тогда обновлять ProgressBar ( индикатор прогресса выполнения алгоритма), допустим цикла, чтобы АЛГОРИТМ ОТ ЭТОГО НЕ ТОРМОЗИЛ. Нужно чтобы
For i:=1 to 10000 do DosomeThing;
выполнялось быстро и при этом процесс визуализировался ProgressBar
У Вас есть какие-нибудь предложения.
p.s. Проблему можно сравнить с индикацией сортировки ProgressBar"ом без торможения алгоритма


 
Толик   (2003-07-28 19:16) [7]

Для того, чтобы поток видел ход изменения значения переменной i, её надо передавать в конструктор потока по ссылке или через указатель.


 
CanBlow   (2003-07-28 19:16) [8]

Понимаете, если делать так
Fi\or i:=1 to 100000 do
begin
if (i mod 100)=0 then PrBar1.Position:=i;
end;

Всё равно будет замедление, из-за того, что в цикле есть
IF и PrBar1.Position. И какая разница, если цикл вынести в поток. Цикл всё равно будет выполнятся медленнее, чем без индикации


 
CanBlow   (2003-07-28 19:18) [9]


> Толик

Так?
Constructor Create(var var1 :TVar1; var2 : TVar2);


 
Толик   (2003-07-28 19:18) [10]

>> Толик © (28.07.03 19:16)
Сорри, по ссылке не пройдёт, так что только через указатель.


 
CanBlow   (2003-07-28 19:19) [11]


> Толик ©

Через указатель это как? Это ^ или Pointer?
Например?


 
Юрий Зотов   (2003-07-28 19:20) [12]

> CanBlow © (28.07.03 19:13)

См. Толик © (28.07.03 18:48)

Схема простая. Когда требуется обновление, поток вызывает PostMessage (но только не SendMessage), посылает нужному окну основного потока сообщение WM_USER+100 (передавая в параметрах позицию ProgressBar"а) и продолжает работать дальше. А окно, получив это сообщение, обновляет позицию. Вот и получается параллельная работа.


 
CanBlow   (2003-07-28 19:21) [13]


> Юрий Зотов © (28.07.03 19:20)

Собщение посылается окну или ProgressBar"у?


 
mrcat   (2003-07-28 19:23) [14]

CanBlow © (28.07.03 19:21)

посылайте кому хотите, главное --- грамотно обработать.


 
CanBlow   (2003-07-28 19:25) [15]


> Юрий Зотов © (28.07.03 19:20)

Если вы имели в виду, что сообщение посылается из основного потока, то ясно, а если из второго, то в том то и проблема, что я не могу получить во втором потоке I, т.е позицию ProgressBar? которую нужно установить.
Мне нужен пример.


 
CanBlow   (2003-07-28 19:26) [16]

Может ссылка на пример есть у кого?


 
Suntechnic   (2003-07-28 19:27) [17]

CanBlow © (28.07.03 19:21)
Собщение посылается окну или ProgressBar"у?


Можешь в доп. поток передать Handle своего ProgressBar-а, а затем через PostMessage управлять им с помощью сообщений PBM_xxx


 
panov   (2003-07-28 19:31) [18]

Разницы нет, в основном потоке ты будешь делать обновление или в дополнительном.
В обоих случаях (для твоего примера) разницы не будет.

А в твой пример надо добавить Application.ProcessMessages; в цикл.


 
Suntechnic   (2003-07-28 19:35) [19]

А в твой пример надо добавить Application.ProcessMessages; в цикл.

Если это добавлять, тогда зачем создавать доп. поток? А уж коль создаём доп. поток, тогда зачем нам Application.ProcessMessages?


 
CanBlow   (2003-07-28 19:36) [20]

Если поставить в цикл Application.ProcessMessages? то интерфейс не будет "подвисать".

Просто скажите мне, какой цикл выполнится быстрее
Первый
For i:=1 to 1000000 do
begin
K:=K+1;
end;

или
Второй

ProgressBar1.Max:=1000000;
For i:=1 to 1000000 do
begin
if (i mod 1000) then ProgressBar1.Position:=I;
K:=K+1;
end;

???????


 
panov   (2003-07-28 19:42) [21]

>Suntechnic © (28.07.03 19:35)
А в твой пример надо добавить Application.ProcessMessages; в цикл.

Если это добавлять, тогда зачем создавать доп. поток? А уж коль создаём доп. поток, тогда зачем нам Application.ProcessMessages?


Вот и я про то же-)

>CanBlow © (28.07.03 19:36)

А сам как думаешь?
Я думаю, что второй. Однозначно.


 
Suntechnic   (2003-07-28 19:42) [22]

CanBlow © (28.07.03 19:36)
Если поставить в цикл Application.ProcessMessages? то интерфейс не будет "подвисать".


Если ты те действия, которые вызывают "подвисание", выносишь в отдельный поток, то UI в любом случае не будет подвисать.



 
CanBlow   (2003-07-28 19:45) [23]


> panov © (28.07.03 19:42)

А вот я думаю, что пустой цикл с одной операцией k:=k+1 выполнится быстрее :-)

> Suntechnic © (28.07.03 19:42)

Да мне пофигу на UI? мне надо, чтобы цикл выполнился за минимальное время и его не тормозили дополнительные инструкции внутри цикла.

Может индикацию в основной поток, а алгоритм - во второй? :-)
Ещё шутники есть?


 
CanBlow   (2003-07-28 19:46) [24]


> CanBlow © (28.07.03 19:36)

(I mod 1000) = 0
Очепятался... :)


 
CanBlow   (2003-07-28 19:53) [25]

А что быстрее вызывать в цикле PrBar1.Position или PostMessage(Hnadle,PBM_SETPOS,NEwPos,0)? PostMessage "не ждёт" "поттверждения доставки"?


 
panov   (2003-07-28 19:54) [26]

С циклами у меня тоже опечатка.

А общий принцип дя твоего случая может выглядеть так:

В потоке выполняются длительные вычисления, периодически посылается PostMessage в основной поток, в котором один из параметров(WParam или LParam) - текущее смещение бегунка в ProgressBar.


 
CanBlow   (2003-07-28 19:56) [27]

Всем огромное спасибо. Помогли разгрести кашу в голове и навести резкость в вопросе. Буду переписывать относительно новых тенденций :-)!!!


 
Юрий Зотов   (2003-07-28 22:48) [28]

> CanBlow © (28.07.03 19:56)

Тут принцип такой - визуальный интерфейс юзера оставляем в главном потоке, а "невидимые" вычисления выносим в дополнительный. Закончив очередную порцию вычислений, дополнительный поток уведомляет об этом главный и продолжает работать. А главный, получив уведомление, обновляет интерфейс.


 
jack128   (2003-07-28 23:39) [29]

PostMessage без Application.ProcessMessages нечего не даст..
Есть два варианта
1)

> panov © (28.07.03 19:31)

то есть

for i := 0 to Max do
begin
DoSameThing();
if i mod <выбирай сам> = 0 then
begin
ProgressBar.StepIt;
Application.ProcessMessages;
end;
end;

2)
выноси все в Tthread.Execute() (не забывая про синхронизацию)
procedure TmyThread.Execute();
begin
for i := 0 to Max do
begin
DoSameThing();
if i mod <сам выбирай> = 0 then
Synchronize(UpdateProgressbar);
end;
end;

procedure TmyThread.UpdateProgressbar();
begin
Form1.ProgressBar1.StepIt;
end;

первый способ проще, второй теоритически быстрее...



 
Suntechnic   (2003-07-28 23:58) [30]

>jack128 © (28.07.03 23:39)
Тут народ только и толкует о том, что SendMessage использовать не выгодно т.к. доп. поток будет ждать завершения обновления прогресс бара (на самом деле не всё так печально, потому как обновление всё одно будет происходить через очередь сообщений, но суть вещей это не меняется). А Synchronize синхронизирует доступ к объектам VCL именное через SendMessage. Кода в этой ветке упоминали PostMessage, то имели ввиду Ваш второй вариант, но вместо Synchronize(UpdateProgressbar); что то типа PostMessage(Form1.Handle, WM_USER + something, our_parameters) или PostMessage(Form1.ProgressBar1.Handle, PBM_xxx, ...)


 
CanBlow   (2003-07-29 08:21) [31]

Всё сделал через PostMessage в отдельном потоке. Спасибо Вам за помощь.
p.s. Стандартно PrBar1.Position работает через SetPosition, которая обновляет через SendMessage с PBM_SETPOS + несколько проверок в SetPosition. Так что вариант через PostMessage и PBM_SETPOS, который не ожидает доставки сообщения, ускоряет цикл в 3 раза (40 msec. против 120 msec. при 1000000 интераций)


 
jack128   (2003-07-29 12:31) [32]


> Suntechnic © (28.07.03 23:58)

Не уж то вы думаете, что Form1.ProgressBar1.StepIt; это настолько огромный и сложный код и этот код будет существенно влиять на скорость работы основного алгоритма?

Я вовсе не против PostMessage"a как токового, но я против излишнего использования Api(а в данном случаи это, IMHO, лишнее), там где можно использовать VCL...


 
panov   (2003-07-29 13:09) [33]

>jack128 © (29.07.03 12:31)
Form1.ProgressBar1.StepIt выполняется в контексте основного потока, следовательно, пока не обновится ProgressBar, дополнительный поток будет ожидать этого.
PostMessage выполняется очень быстро и дополнительный пото не занят ожиданием.



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

Форум: "Основная";
Текущий архив: 2003.08.11;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.007 c
1-33129
Алексей Петухов
2003-07-30 11:51
2003.08.11
TDBGrid


1-33151
chs2r
2003-07-28 11:05
2003.08.11
CreateFile.. могу ли я использовать как буфер динамический массив


1-33124
Сорокин Семен
2003-07-30 10:37
2003.08.11
FormatCurr


3-33075
LeReve
2003-07-17 17:44
2003.08.11
про TCalientDataSet.ApplyUpdate


3-33078
Maxim_E.
2003-07-17 22:26
2003.08.11
Был бы обработчик события TDBGrid OnChangeColumnWidth он бы помог





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский