Форум: "Основная";
Текущий архив: 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
прямо в конце? Прававильно?
Что - то не получилось переопредилить OnTerminateprocedure 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