Форум: "Основная";
Текущий архив: 2003.06.02;
Скачать: [xml.tar.bz2];
ВнизПро TObject.Free Найти похожие ветки
← →
cheg (2003-05-21 16:39) [0]Как определить, существует ли экземпляр класса, после вызова метода Free, без присвоения ему nil. Например:
...
SomeObject.Free;
...
if (SomeObject это реально существующий обьект?) then...
← →
Anatoly Podgoretsky (2003-05-21 16:42) [1]А зачем, что то неверно в дизайне. Но ответ простой не существует.
← →
MBo (2003-05-21 16:42) [2]>без присвоения ему nil
Чем это плохо?
проще всего FreeAndNil.
← →
Юрий Зотов (2003-05-21 16:46) [3]> Как определить, существует ли экземпляр класса, после вызова
> метода Free, без присвоения ему nil.
Можно и не определять - после вызова Free он точно не существует. Обнуление ссылки нужно не для этого, а для того, чтобы зафиксировать сам факт вызова Free. Вместо "ручной" очистки можно использовать FreeAndNil, а если и такой способ не устраивает, то можно фиксировать вызов Free любым другим способом (логической переменной и т.д.).
← →
Verg (2003-05-21 16:48) [4]
> Как определить, существует ли экземпляр класса, после вызова
> метода Free, без присвоения ему nil.
После вызова метода Free экземпляр не существует однозначно.
Если боишься, что по каой-либо причине Free может не вызваться, то заключай Free в секцию
Obj := Tobj.Create(....;
try
.....
Что-то делаем с Obj
finally
Obj.Free;
end;
......
Далее существует гарантия, что Free вызвался даже в случае "ядерной войны" (Break-ов, exit-ов, goto-ев, exception-ов и т.п.) :))
← →
cheg (2003-05-21 16:55) [5]Например такая ситуация: имееться TMyThread extends TThread, дальше есть переменная MyThr :TMyThread. Создаем поток, при этом проверяем, если он работает, то не будем создавать:
if Assigned(MyThread) and MyThread.isStrated then exit;
MyThread := TMyTread.Create...
После первого запуска потока, на MyThread.isStrated будет вываливать exception. Что делать? лепить какие-то переменные watcherы.
← →
Skier (2003-05-21 16:58) [6]TThread.OnTerminate не поможет ?
← →
Verg (2003-05-21 17:04) [7]
> Например такая ситуация: имееться TMyThread extends TThread,
> дальше есть переменная MyThr :TMyThread. Создаем поток,
Какая переменная? Локальная? Глобальная? Поле объекта?
> при этом проверяем, если он работает, то не будем создавать:
> if Assigned(MyThread) and MyThread.isStrated then exit;
> MyThread := TMyTread.Create...
Если теебе нужно определять отработал ли поток или нет, и вслучае "да" запустить его по-новой, то, например, создай поток с FreeOnTerminate=false и определяй лишь только состояние его Handl-а (как EVENT-а)- сброшен - поток работает, естановлен - поток завершился, можно его фрякать и создавать/запускать новый.
Хотя тут полно других вариантов, но определить вне контекста существует ли объект или "какой-то дядя" егя фрякнул - не существует.
← →
Юрий Зотов (2003-05-21 17:05) [8]Не вызывайте Free сами. Вместо этого выставляйте FreeOnTerminate и объект уничтожится автоматически. Но перед этим он вызовет OnTerminate - вот там и очищайте Вашу ссылку.
← →
Verg (2003-05-21 17:05) [9]
> Хотя тут полно других вариантов, но определить вне контекста
> существует ли объект или "какой-то дядя" егя фрякнул - не
> существует.
Я имел ввиду способа не существует
← →
cheg (2003-05-21 17:15) [10]2Verg.
...Если теебе нужно определять отработал ли поток или нет, и вслучае "да" запустить его по-новой, то, например, создай поток с FreeOnTerminate=false
Согласен. Спасибо.
← →
Verg (2003-05-21 17:27) [11]А вообще, лучше бы в таком случае чтобы поток не завершался, а переходил в состояние ожидания команды на новую обработку. И вот почему, мне кажется, что для системы создание потока - это "гружево", не даром же, например, многие сервера (да и я сам таким приемом пользуюсь) держат кэш потоков, и в случае надобности "аттачат" новую задачу к одному из ожидающих в кэше потоку (говорят "фас!", так сказать), а если новых задачь не поступало давно, то менеджер потоков постепенно освобождает потоки в кэше. Такой прием заметно (как показала практика) повышает производительность задачи.
← →
Юрий Зотов (2003-05-21 17:32) [12]> cheg © (21.05.03 17:15)
О, Господи! Все же наоборот!
1. Создаем поток так:
if MyThr = nil then
begin
MyThr := TMyThread.Create(True);
with MyThr do
begin
FreeOnTerminate := True;
OnTerminate := OnTerminateHandler;
Resume
end
end;
2. В OnTerminateHandler одна строка:
MyThr := nil;
И все дела.
← →
Verg (2003-05-21 17:40) [13]
> Юрий Зотов © (21.05.03 17:32)
.....
> OnTerminateHandler;
Вариант хороший, только есть один момент:
если OnTerminateHandler - это метод объекта, содержащего в полях MyThr, то должна существовать какая либо гарантия, что к моменту когда поток завершится и вызовет названный метод, сам объект владеющий данным методом будет существовать тоже. Это условие иногда не выполняется, например, при выходе из приложения.
Хотя при соблюдении определенных правил, такой метод тоже хорош, особенно для наглядности.
← →
Юрий Зотов (2003-05-21 17:54) [14]> Verg © (21.05.03 17:40)
Если бы это было поле, я написал бы FMyThr. А просто MyThr - это глобальная переменная в секции implementation. Что снимает все проблемы.
← →
Verg (2003-05-21 18:04) [15]
>... я написал бы F....
Учтем-с, ладно :-)
Тогда осталось определиться с очередью сообщений - ведь OnTerminate вызывается методом Synchronize, а это накладывает определенные обязательства на владельца потока :-) - он
должен обрабатывать очередь сообщений...
← →
Юрий Зотов (2003-05-21 18:12) [16]> Verg © (21.05.03 18:04)
Если уж говорить о теории, то надо просто реализовать TMyThread в виде синглтона и более ни о чем не заботиться. А если говорить о конкретном вопросе конкретного автора, то есть основания полагать, что поток создается из кода формы.
← →
rounin (2003-05-21 18:16) [17]Verg © (21.05.03 17:40)
Ты можешь обнулить FMyThr.OnTerminate в деструкторе
объекта, содержащего поле FMyThr
Verg © (21.05.03 18:04)
Сообщение M_EXECPROC посылается отнюдь не владельцу
твоего потока. См. исходники
← →
Verg (2003-05-21 18:16) [18]Я не о теории, я о ...
"Мне сказали - иди к Маше, а что от этого дети могут быть - не сказали...." :)))
← →
Verg (2003-05-21 18:25) [19]
> Сообщение M_EXECPROC посылается отнюдь не владельцу
> твоего потока. См. исходники
Правильно, оно посылается окну, созданому в контексте создания потока, а значит выполнение (обработка) CM_EXECPROC будет произведена только при обращении к очереди сообщений тем же контекстом (контестом создателя TThread). И пройдет не раньше, чем тот самый поток-создать (владелец) обратится к очереди сообщений (а она к этому моменту будет находится в состоянии QS_SENDMESSAGE). А поток вызвавший Synchronize будет спать и ждать этого "ключевого" для него события.
Не веришь - спроси у Дж. Рихтера.
← →
Verg (2003-05-21 18:29) [20]Теперь о...
> Ты можешь обнулить FMyThr.OnTerminate в деструкторе
> объекта, содержащего поле FMyThr
InterlockedExchange ?
CriticalSection ?
Каким образом "обнулять" такую переменную?
← →
rounin (2003-05-21 18:33) [21]Зачем??? Просто
if Assigned(FMyThr) then FMyThr.OnTerminate := nil;
К полю FOnTerminate нет обращений в контексте твоего потока.
← →
Verg (2003-05-21 18:40) [22]
> К полю FOnTerminate нет обращений в контексте твоего потока.
if Assigned(FOnTerminate) then Synchronize(CallOnTerminate);
"См. исходники" (С) rounin
← →
rounin (2003-05-21 18:48) [23]Да, действительно, в DoTerminate есть чтение.
Но в данном случае на улов рыбы это никак не влияет.
← →
Verg (2003-05-21 20:58) [24]Влияет, даже в однопроцессорной "жигули" можно наступить на грабли, а в многопроцессорном "мереседесе" можне вообще влететь в жесткую штангу..., но... не хочу обострять...
Видимо Pink Floyd и "Shine on You Crazy Diamond " тому виной.....
← →
rounin (2003-05-21 21:47) [25]Одновременный доступ к одним и тем же
данным из разных потоков сам по себе не есть зло.
Зло состоит в последствиях, которые он может вызвать.
В данном случае легко прикинуть возможные варианты и понять,
что синхронизации не требуется.
Аналогично, например, поле FTerminated потока
устанавливается в одном потоке, а читается в другом.
Безо всякой синхронизации.
← →
Спрашивающий (2003-05-22 02:27) [26]>cheg ©
Не используй данную проверку if Assigned() лучше проверяй по
if XXX =nil.Вы будете в недоумении скажете да это же одно и тоже,
да теоретически но не практически. Можете разбить мой коментарий в пух и прах но я останусь при своем мнени.
p.s. Из горького опыта.
← →
Verg (2003-05-22 09:26) [27]
> Одновременный доступ к одним и тем же
> данным из разных потоков сам по себе не есть зло.
> Зло состоит в последствиях, которые он может вызвать.
Хорошо, давай рассмотрим кусок кода модуля Classes D4:
procedure TThread.CallOnTerminate;
begin
FOnTerminate(Self);
end;
procedure TThread.DoTerminate;
begin
if Assigned(FOnTerminate) then Synchronize(CallOnTerminate);
end;
Допустим поток проверил, что FOnTerminate<>nil и пошел выполнять
Synchronize. После этой проверки переключение потоков прекратилось что ли? Или кто-то как-то запретил доступ к полю FOnTerminate? Нет. Так где гарантии, что к моменту выполнения CallOnTerminate (а точнее к моменту Sendmessage(ThreadWindow, CM_EXECPROC....) тот, главный поток не обнулит FOnTerminate?
Аргументируй.
Для корректной работы такой конструкции нужна еще одна проверка
if assigned - в процедуре CallOnTerminate, так как она-то выполняется строго в контексте главного потока.
Это и было, между прочим, поправлено, по крайней мере в D6. А в D4 - нет, и поток будет с определенной вероятностью вызывать Access viol...
← →
rounin (2003-05-22 10:17) [28]В D4 так делать нельзя, ты абсолютно прав.
У меня D5 :)
Приношу извинения.
← →
VaS (2003-05-22 10:38) [29]Эээ. Зачем хэндлер? В деструкторе класса нитки и обнулять глоб. переменную.
← →
Юрий Зотов (2003-05-22 10:47) [30]> VaS © (22.05.03 10:38)
> В деструкторе класса нитки и обнулять глоб. переменную.
Угу. Из секции implementation другого модуля...
А почему она должна быть в секции implementation другого модуля? Потому что есть такое понятие - безопасный стиль программрования. О котором тут и говорилось.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2003.06.02;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.009 c