![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как главному потоку узнать что другой уже закончил работу. [D7, Win95/98, Win2k, WinXP]
Kolan © (2005-07-05 14:31:00)Здравствуйте:
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-06 09:36:00) [1]
> begin...end © (06.07.05 09:19) [38]
> как выяснилось, не вс
да, не всегда.
вот реальная ситуация :
ДЛЛ собрана без ран-тайм-пакетов, она самодостаточна, ее код будет использовать код/данные собственных экз-ров юнитов System (где объявлена глоб.переменная MainThreadId) и Classes (где объявлены КС и SyncList)
теперь хост-процесс в доп.трэде грузит эту ДЛЛ, в ходе ее иниц-ции (в контексте загружающеготрэда) произойдет иниц-ия данных юнита System, в т.ч. будет выполнена строка
initialization
..
MainThreadID := GetCurrentThreadID; //текущий трэд - не основной !!! со всеми вытекающими последствиями ...
Fay (2005-07-06 09:26:00) [2]2 begin...end © (06.07.05 9:19) [38]
Какой ужас. Как-то я по диагонали читал. 8)
Спасибо! Теперь я лучше знаю, за что не люблю всякие TThread-ы. 8)
begin...end (2005-07-06 09:19:00) [3]> Fay © (06.07.05 9:11) [37]
Насколько я понимаю, метод, подлежащий синхронизации, помещается в глобальный список SyncList, включается Event (SygnalSyncEvent), и метод из списка (в то время, когда у Application очередь сообщений пуста) выполняется внутри Application.Idle (из него вызывается функция Classes.CheckSynchronize) в контексте главного (как выяснилось, не всегда) потока.
Fay (2005-07-06 09:11:00) [4]2 begin...end © (06.07.05 9:05) [36]
А в чём ещё? Я не очень внимательно изучал эти Synchronize-ы, т.к. не пользуюсь никогда.
Видимо пропустил что-то важное.
begin...end (2005-07-06 09:05:00) [5]> Fay © (05.07.05 15:11) [11]
> Крит. секция не меняет коду поток.
Кстати, а причём здесь крит. секция? Смысл Synchronize-то не только в этом.
Digitman (2005-07-06 09:04:00) [6]
> Какие ресурсы являются для нити своими?
те которые нить создала/заняла в расчете на дальнейшее "монопольное" использование
например, подразумевается, что осн.трэд, создавший некий визуальный VCL-контрол, в дальнейшем (по ходу исполнения программы) ответственен за управление этим контролом, вплоть до его уничтожения, и что ни один другой трэд процесса не вправе обратиться к этому контролу в своем контексте без "ведома" осн.трэда
Fay (2005-07-06 08:54:00) [7]2 Digitman © (06.07.05 8:45) [33]
М.б. я туплю, но я что-то не врубаюсь. Какие ресурсы являются для нити своими?
При некотором напряжении я могу представить ресурсы процеса, дальше мысль обрывается.
Digitman (2005-07-06 08:45:00) [8]
> 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:25:00) [9]2 Kolan © (05.07.05 23:41) [31]
Нормально решение, хотя я бы воспользовался быRegisterWindowMessageвместоWM_USER + 100.
Kolan (2005-07-05 23:41:00) [10]Добрый вечер,
Еще пара вопросов:
В процессе заполнения записи возникают ошибки
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-05 17:46:00) [11]2 Digitman © (05.07.05 17:16) [29]
Я и говорю, что не упоминается.
Собственно это мне и кажется странно - почему не всем нитям нужно заходить в CS? Мне такое поведение не кажется очевидным.
Digitman (2005-07-05 17:16:00) [12]
> Fay © (05.07.05 17:10) [28]
а причем здесь крит.секция ?
где в
if GetCurrentThreadID = MainThreadID then
ASyncRec.FMethod
хоть какое-то упоминание крит.секции ?
никто никуда в дан.случае не "ломится" - тек.трэд, обнаружив совпадение своего Id со значением в глоб.переменной System.MainThreadId, с полным правом вызывает указанный метод в своем же контексте
Fay (2005-07-05 17:10:00) [13]Digitman © (05.07.05 15:41) [25]
Critical Section. В данном случае "ThreadLock".
Digitman (2005-07-05 16:24:00) [14]
> Kolan © (05.07.05 15:48) [26]
чем [7] не нравится ? там никаких OnTerminate и FreeOnTerminate ..
создал объект и ждешь завершения потока, созданного объектом (после чего с полным правом и уверенностью уничтожаешь объект), в ходе ожидания нормально и оперативно реагируешь на события/сообщения ввода/вывода ..
Kolan (2005-07-05 15:48:00) [15]
> 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 15:41:00) [16]
> Fay © (05.07.05 15:30) [20]
> Доп. потоки должны ломиться в CS, а основной нет. Он волшебный?
что есть "CS" в дан.случае ?
Digitman (2005-07-05 15:40:00) [17]
> Если я снова вызову Create. То наверно потеряю ссылку на
> пред. попоток?
конечно потеряешь ... если результатом очередного вызова конструктора затрешь предыдущее значение переменной, хранящей ссылку на еще существующий объект
> Сейчас сделал FreeOnTerminate
в дан.случае, конечно, можно и авторазрушением воспользоваться, поскольку тебе не нужен сам объект, а интересует лишь финальное состояние структуры, переданной по ссылке трэду для обработки
но я бы не рекомендовал
> в конце Execute потока Thread.Terminate. Нормально?
нормально.
но Thread.Terminate в дан.ситуации нужен как корове седло, ибо все что он делает - взводит флаг Thread.Terminated, в определении состоянии которого (как факта, сигнализирующего трэду о необходимости как можно быстрее "закруглиться по хозяйству") по идее д.б. заинтересован сам трэд, который у тебя уже пошел на штатное завершение и ни в каких флагах не нуждается
> Как её выполнить по событию Terminate
ее не надо выполнять.
это защищенный вирт.метод объекта TThread
если он не перекрыт тобой, класс TThread в теле DoTerminate автоматически вызовет (синхронно с MainThreadId) обработчик события OnTerminate, если он назначен тобой на этот момент
begin...end (2005-07-05 15:36:00) [18]Добавление к [21]: метод MyObject.MyMethod должен соответствовать типу TNotifyEvent.
Fay (2005-07-05 15:34:00) [19]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:33:00) [20]> Kolan © (05.07.05 15:29) [19]
> И в конце Execute потока Thread.Terminate.
А смысл?
> А c этим никак не разбирусь. Можно пример.
MyThread.OnTerminate := MyObject.MyMethod, где MyMethod -- метод объекта MyObject, который требуется выполнить по событию OnTerminate.