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

Вниз

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

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

Наверх




Память: 0.57 MB
Время: 0.013 c
1-1120468392
PEKAHT
2005-07-04 13:13
2005.07.25
Скролинг в TreeView


1-1120744238
Stalker01
2005-07-07 17:50
2005.07.25
Форма поверх всех окон


1-1120814383
yuran
2005-07-08 13:19
2005.07.25
Как определить что пользователь начал обращаться к дисководу?


14-1119957288
ReaderT_T
2005-06-28 15:14
2005.07.25
Книги


4-1117137483
cherrex
2005-05-26 23:58
2005.07.25
OCR для DELPHI





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