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

Вниз

Как главному потоку узнать что другой уже закончил работу.   Найти похожие ветки 

 
Kolan ©   (2005-07-05 14:31) [0]

Здравствуйте:
 1. Есть структура.
MeasurmentDataRec

 2. Есть тип - указатель на такую структуру. MeasurmentDataRec: PMeasurmentData

 3. Есть поток у которого поле - это указатель на структуру
TMeasurmentThread = class(TThread)
 private
 protected
 public
   FMeasurmentDataRec: PMeasurmentData;
   constructor Create(CreateSuspended: Boolean;
     MeasurmentDataRec: PMeasurmentData);

 4. При создании потока в его поле передается указатель на структуру.
 5. Поток работает с переданной структурой(заполняет её).
 
 6. После того как поток закончил работу надо показать результат пользователю для этого используется процедура
ShowMeasurmentResults(MeasurmentDataRec: PMeasurmentData)
 
Вопрос:
 1. Как запустьть процедуру ShowMeasurmentResults по окончании работы потока.

 2. Как убить поток по окончании его работы.


 
Digitman ©   (2005-07-05 14:34) [1]


> 1. Как запустьть процедуру ShowMeasurmentResults по окончании
> работы потока


например, вызвать ее в обработчике события TThread.OnTerminate


>  2. Как убить поток по окончании его работы


MyThread.Free


 
Kolan ©   (2005-07-05 14:47) [2]

Забыл сказать
 ShowMeasurmentResults находится в модуле главной формы. И модуль где поток ничего не знает о её сушествование.
Может надо прередать её указатель?

MyThread.Free
 прямо в конце? Прававильно?

Что - то не получилось переопредилить OnTerminate
procedure OnTerminate; override;

Ошибка
Method "OnTerminate" not found in base class

MyThread.OnTerminate есть ?


 
Digitman ©   (2005-07-05 14:52) [3]


> MyThread.Free
>  прямо в конце? Прававильно?


конец концу - рознь.
что ты подразумеваешь под "концом" ?


> Что - то не получилось переопредилить OnTerminate


это событие, а не метод


 
begin...end ©   (2005-07-05 14:52) [4]

> Kolan ©   (05.07.05 14:47) [2]

> ShowMeasurmentResults находится в модуле главной
> формы. И модуль где поток ничего не знает о её
> сушествование.
> Может надо прередать её указатель?

Можно и так.
А может, просто в список uses модуля потока добавить модуль формы?
Есть и ещё вариант: по окончании работы потока посылать форме сообщение, а в обработчике этого сообщения формы запускать ShowMeasurmentResults. Но для этого потоку нужно будет знать, КУДА посылать сообщение, а значит, при его создании нужно будет передавать хэндл окна формы.

> MyThread.OnTerminate есть ?

Есть. Только это не метод, а свойство. И свойству достаточно присвоить ссылку на метод.


 
Fay ©   (2005-07-05 15:00) [5]

begin...end ©   (05.07.05 14:52) [4]
А в каком потоке выполняется OnTerminate ?


 
begin...end ©   (2005-07-05 15:02) [6]

> Fay ©   (05.07.05 15:00) [5]

В основном, а что?


 
Digitman ©   (2005-07-05 15:02) [7]

можно еще сделать так (без использования OnTerminate):

//стартуем доп.трэд
MyThread := TMyThread.Create(параметры);
try
//пока приложение работает
while not Application.Terminated do
//ждем либо завершения потока либо любого сообщения в очереди сообщений окнам тек.трэда
 case MsgWaitForMultipleObjects(1, MyThread.Handle, False, INFINITE, QS_ALLINPUT) of
 WAIT_OBJECT_0: break; //доп.трэд завершил свою работу
 WAIT_OBJECT_0 + 1: Application.ProcessMessages; //обработаем сообщения окнам
finally
 MyThread.Free;
end;


 
Digitman ©   (2005-07-05 15:03) [8]


> В основном, а что?


не обязательно, но как правило


 
Fay ©   (2005-07-05 15:07) [9]

2 begin...end ©   (05.07.05 15:02) [6]
2 Digitman ©   (05.07.05 15:03) [8]

Точно. Нашёл
procedure TThread.DoTerminate;
begin
 if Assigned(FOnTerminate) then
   Synchronize(CallOnTerminate);
end;


Это, конечно, не "в основном", но уже кое-что.


 
begin...end ©   (2005-07-05 15:10) [10]

> Digitman ©   (05.07.05 15:03) [8]

В каком случае не в основном?


 
Fay ©   (2005-07-05 15:11) [11]

begin...end ©   (05.07.05 15:10) [10]
В любом. Крит. секция не меняет коду поток.


 
Digitman ©   (2005-07-05 15:17) [12]


> В каком случае не в основном?


в случае когда MainThreadID содержит значение идентификатора трэда, инициализировавшего экз-р модуля System


 
Digitman ©   (2005-07-05 15:19) [13]

цитата (Д7):

class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord);
var
 SyncProc: TSyncProc;
begin
 if GetCurrentThreadID = MainThreadID then
   ASyncRec.FMethod
...

т.е. при выполнении условия GetCurrentThreadID = MainThreadID метод FMethod тут же будет синхронно выполнен в контексте того трэда, который вызвал Synchronize


 
begin...end ©   (2005-07-05 15:21) [14]

> Fay ©   (05.07.05 15:11) [11]

Не в любом.

> Digitman ©   (05.07.05 15:17) [12]

ОК, ясно.


 
Digitman ©   (2005-07-05 15:21) [15]


> содержит значение идентификатора трэда


читать как содержит значение идентификатора неосновного трэда


 
Digitman ©   (2005-07-05 15:24) [16]


> begin...end ©   (05.07.05 15:21) [14]


т.е. наивно полагая, что synchronize синхронизирует вып-е указ.метода с осн.трэдом процесса обязательно и безусловно, можно в ряде ситуаций и вляпаться


 
Fay ©   (2005-07-05 15:24) [17]

2 Digitman ©   (05.07.05 15:21) [15]
if GetCurrentThreadID = MainThreadID then
  ASyncRec.FMethod

А это правильно?


 
Digitman ©   (2005-07-05 15:25) [18]


> Fay ©   (05.07.05 15:24) [17]


> А это правильно?


а почему нет ?


 
Kolan ©   (2005-07-05 15:29) [19]


> конец концу - рознь.
> что ты подразумеваешь под "концом" ?

Ну все он отработал и мне не нужен до следующего раза. Если я снова вызову Create. То наверно потеряю ссылку на пред. попоток?Сейчас сделал FreeOnTerminate. И в конце Execute потока Thread.Terminate. Нормально?


> Есть. Только это не метод, а свойство. И свойству достаточно
> присвоить ссылку на метод.


А c этим никак не разбирусь. Можно пример.

Вот есть процедура

TMeasurmentThread = class(TThread)
 private
 protected
 public
  {...}
   procedure DoTerminate;
 end;


Как её выполнить по событию Terminate.


 
Fay ©   (2005-07-05 15:30) [20]

Доп. потоки должны ломиться в CS, а основной нет. Он волшебный?


 
begin...end ©   (2005-07-05 15:33) [21]

> Kolan ©   (05.07.05 15:29) [19]

> И в конце Execute потока Thread.Terminate.

А смысл?

> А c этим никак не разбирусь. Можно пример.

MyThread.OnTerminate := MyObject.MyMethod, где MyMethod -- метод объекта MyObject, который требуется выполнить по событию OnTerminate.


 
Fay ©   (2005-07-05 15:34) [22]

Kolan ©   (05.07.05 15:29) [19]
Можно так.
TMeasurmentThread = class(TThread)
private
 procedure BuBuBu(Sender : TObject);
protected
public
 constructor Create(CreateSuspended: Boolean); override;
 {...}
  procedure DoTerminate;
end;

....
constructor TMeasurmentThread.Create(CreateSuspended: Boolean);
begin
 inherited;
 OnTerminte := BuBuBu;
end;

procedure TMeasurmentThread.BuBuBu(Sender : TObject);
begin
 DoTerminate;
end;

....


 
begin...end ©   (2005-07-05 15:36) [23]

Добавление к [21]: метод MyObject.MyMethod должен соответствовать типу TNotifyEvent.


 
Digitman ©   (2005-07-05 15:40) [24]


> Если я снова вызову Create. То наверно потеряю ссылку на
> пред. попоток?


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


> Сейчас сделал FreeOnTerminate


в дан.случае, конечно, можно и авторазрушением воспользоваться, поскольку тебе не нужен сам объект, а интересует лишь финальное состояние структуры, переданной по ссылке трэду для обработки

но я бы не рекомендовал


> в конце Execute потока Thread.Terminate. Нормально?


нормально.
но Thread.Terminate в дан.ситуации нужен как корове седло, ибо все что он делает - взводит флаг Thread.Terminated, в определении состоянии которого (как факта, сигнализирующего трэду о необходимости как можно быстрее "закруглиться по хозяйству") по идее д.б. заинтересован сам трэд, который у тебя уже пошел на штатное завершение и ни в каких флагах не нуждается


> Как её выполнить по событию Terminate


ее не надо выполнять.
это защищенный вирт.метод объекта TThread

если он не перекрыт тобой, класс TThread в теле DoTerminate автоматически вызовет (синхронно с MainThreadId) обработчик события OnTerminate, если он назначен тобой на этот момент


 
Digitman ©   (2005-07-05 15:41) [25]


> Fay ©   (05.07.05 15:30) [20]
> Доп. потоки должны ломиться в CS, а основной нет. Он волшебный?


что есть "CS" в дан.случае ?


 
Kolan ©   (2005-07-05 15:48) [26]


> begin...end ©   (05.07.05 15:33) [21]
> > Kolan ©   (05.07.05 15:29) [19]
>
> > И в конце Execute потока Thread.Terminate.
>
> А смысл?

Перефразирую: Что мне делать когда работа потока уже завершена и осталось вызавать процедуру вывода на экран.

Причём дальше может понадобится опять создать поток итд...

те если поток не удалить(или вот что с ним сделать надо?) то при следующем вызове

MeasurmentThread := TMeasurmentThread.Create(False, MeasurmentDataRec);

MeasurmentThread - перетрется и все и я не смогу его удалить.

Может в конце работы потока посылать сообщение главномуокну. А по появлениии такого сообщения удалять поток и делать вывод на экран?


 
Digitman ©   (2005-07-05 16:24) [27]


> Kolan ©   (05.07.05 15:48) [26]


чем [7] не нравится ? там никаких OnTerminate и FreeOnTerminate ..

создал объект и ждешь завершения потока, созданного объектом (после чего с полным правом и уверенностью уничтожаешь объект), в ходе ожидания нормально и оперативно реагируешь на события/сообщения ввода/вывода ..


 
Fay ©   (2005-07-05 17:10) [28]

Digitman ©   (05.07.05 15:41) [25]
Critical Section. В данном случае "ThreadLock".


 
Digitman ©   (2005-07-05 17:16) [29]


> Fay ©   (05.07.05 17:10) [28]


а причем здесь крит.секция ?

где в

if GetCurrentThreadID = MainThreadID then
 ASyncRec.FMethod

хоть какое-то упоминание крит.секции ?

никто никуда в дан.случае не "ломится" - тек.трэд, обнаружив совпадение своего Id со значением в глоб.переменной System.MainThreadId, с полным правом вызывает указанный метод в своем же контексте


 
Fay ©   (2005-07-05 17:46) [30]

2 Digitman ©   (05.07.05 17:16) [29]

Я и говорю, что не упоминается.
Собственно это мне и кажется странно - почему не всем нитям нужно заходить в CS? Мне такое поведение не кажется очевидным.


 
Kolan ©   (2005-07-05 23:41) [31]

Добрый вечер,
Еще пара вопросов:

В процессе заполнения записи возникают ошибки
 
 if RealyOverflow >= 50 then
     raise EConductivityRelayOverflowError{...}


Так как теперь всё это в отдельном потоке то как я понял там они и остаются. Как передпть их главному потоку?

И еще я хочу показать прогресс заполнения записи. Для этого планирую отправлять сообщение с прогрессом.
Это нормально?

PS Сигнализацию конца заполнения сделал с помощью сообщений.

const
 SX_MEASURINGFINISHED = WM_USER + 100;


В конце

PostMessage(FWindowHandle, SX_MEASURINGFINISHED, 0, 0);

В главной форме

procedure TMainForm.SXMeasuringFinished(var Msg: TMessage);
begin
 MeasurmentManager.FinishMeasuring;
 {Грубо говоря MeasurmentThread.Terminate}
 ShowMeasurmentResults(MeasurmentManager.CurrentMeasurment);
end;


 
Fay ©   (2005-07-06 08:25) [32]

2 Kolan ©   (05.07.05 23:41) [31]
Нормально решение, хотя я бы воспользовался бы RegisterWindowMessage вместо WM_USER + 100.


 
Digitman ©   (2005-07-06 08:45) [33]


> Fay ©   (05.07.05 17:46) [30]


> почему не всем нитям нужно заходить в CS?


зачем же нити заходить в КС, если по алгоритму она обращается к своим ресурсам ?


> Kolan ©   (05.07.05 23:41) [31]



> Как передпть их главному потоку?


например, так :

TMyThread = class(TThread)
..
public
 ExcptObj: TObject;
end;

procedure TMyThread.Execute;
begin
 try
 ..
 except
   ExcptObj := AcquireExceptionObject;
 end;
end;

..

var
E: TObject;
..  
MyThread := TMyThread.Create(параметры);
try
while not Application.Terminated do
case MsgWaitForMultipleObjects(1, MyThread.Handle, False, INFINITE, QS_ALLINPUT) of
WAIT_OBJECT_0: break;
WAIT_OBJECT_0 + 1: Application.ProcessMessages;
finally
E := MyThread.ExcptObj;
MyThread.Free;
end;
if Assigned(E) then
 raise Exception(E)
else
 ShowMeasurmentResults(..);


 
Fay ©   (2005-07-06 08:54) [34]

2 Digitman © (06.07.05 8:45) [33]
М.б. я туплю, но я что-то не врубаюсь. Какие ресурсы являются для нити своими?
При некотором напряжении я могу представить ресурсы процеса, дальше мысль обрывается.


 
Digitman ©   (2005-07-06 09:04) [35]


> Какие ресурсы являются для нити своими?


те которые нить создала/заняла в расчете на дальнейшее "монопольное" использование

например, подразумевается, что осн.трэд, создавший некий визуальный VCL-контрол, в дальнейшем (по ходу исполнения программы) ответственен за управление этим контролом, вплоть до его уничтожения, и что ни один другой трэд процесса не вправе обратиться к этому контролу в своем контексте без "ведома" осн.трэда


 
begin...end ©   (2005-07-06 09:05) [36]

> Fay ©   (05.07.05 15:11) [11]
> Крит. секция не меняет коду поток.

Кстати, а причём здесь крит. секция? Смысл Synchronize-то не только в этом.


 
Fay ©   (2005-07-06 09:11) [37]

2 begin...end © (06.07.05 9:05) [36]
А в чём ещё? Я не очень внимательно изучал эти Synchronize-ы, т.к. не пользуюсь никогда.
Видимо пропустил что-то важное.


 
begin...end ©   (2005-07-06 09:19) [38]

> Fay ©   (06.07.05 9:11) [37]

Насколько я понимаю, метод, подлежащий синхронизации, помещается в глобальный список SyncList, включается Event (SygnalSyncEvent), и метод из списка (в то время, когда у Application очередь сообщений пуста) выполняется внутри Application.Idle (из него вызывается функция Classes.CheckSynchronize) в контексте главного (как выяснилось, не всегда) потока.


 
Fay ©   (2005-07-06 09:26) [39]

2 begin...end ©   (06.07.05 9:19) [38]
Какой ужас. Как-то я по диагонали читал. 8)
Спасибо! Теперь я лучше знаю, за что не люблю всякие TThread-ы. 8)


 
Digitman ©   (2005-07-06 09:36) [40]


> begin...end ©   (06.07.05 09:19) [38]



> как выяснилось, не вс


да, не всегда.

вот реальная ситуация :

ДЛЛ собрана без ран-тайм-пакетов, она самодостаточна, ее код будет использовать код/данные собственных экз-ров юнитов System (где объявлена глоб.переменная MainThreadId) и Classes (где объявлены КС и SyncList)

теперь хост-процесс в доп.трэде грузит эту ДЛЛ, в ходе ее иниц-ции (в контексте загружающего трэда) произойдет иниц-ия данных юнита System, в т.ч. будет выполнена строка

initialization
..

MainThreadID := GetCurrentThreadID; //текущий трэд - не основной !!! со всеми вытекающими последствиями ...



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

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

Наверх




Память: 0.58 MB
Время: 0.043 c
1-1120460209
maktub
2005-07-04 10:56
2005.07.25
Преобразование форматов форм


14-1120065593
Хинт
2005-06-29 21:19
2005.07.25
Мобильный телефон


14-1120073268
Profi
2005-06-29 23:27
2005.07.25
Как учтановить свой компонент в Delphi 2005?


4-1117345046
NikNet
2005-05-29 09:37
2005.07.25
Как внутри ASM кода объявить PCHAR строку?


1-1120664264
Igor_thief
2005-07-06 19:37
2005.07.25
Как из строкового 19,10 перевести в вещественное 19, 10 без ...