Форум: "Прочее";
Текущий архив: 2008.06.08;
Скачать: [xml.tar.bz2];
ВнизМногопоточность и Delphi Найти похожие ветки
← →
Пробегал2... (2008-04-25 15:26) [40]Loginov Dmitry © (25.04.08 13:40) [37]
В конце TMyThread.Execute (или в деструкторе) выполняется присвоение MyThread := nil
о боже. Ты вообще понимаешь что делаешь? Блин, и кто-то говорил о профессионализме... В методах классах обращаться к конкретному экземпляру класса?
Игорь Шевченко © (25.04.08 14:01) [38]
Тут в ветке где-то про чтение Рихтера говорили. Нафига читать Рихтера, если он в Delphi ни ухом ни рылом ?
я пожалуй даже отвечать не буду.
← →
Loginov Dmitry © (2008-04-25 15:29) [41]
> что является главным признаком фактического завершения исполнения
> поточной функции.
Возможно возможно...
Что же по Вашему является "главным признаком фактического завершения исполнения поточной функции", и как это "что" использовать в данной ситуации?
← →
Loginov Dmitry © (2008-04-25 15:30) [42]
> о боже. Ты вообще понимаешь что делаешь? Блин, и кто-то
> говорил о профессионализме... В методах классах обращаться
> к конкретному экземпляру класса?
Вот и объясни мне, как здесь можно выкрутиться без подобных извращений!
← →
Сергей М. © (2008-04-25 15:45) [43]
> Loginov Dmitry © (25.04.08 15:29) [41]
Признаком фактического завершения поточной функции является либо вызов ф-ции ExitThread() либо вызов машинструкции RET верхнего уровня вложенности.
← →
Пробегал2... (2008-04-25 15:59) [44]Loginov Dmitry © (25.04.08 15:30) [42]
Вот и объясни мне, как здесь можно выкрутиться без подобных извращений!
тебе что нужно? Завершить поток? Так сделай ему Terminate, поток должен своевременно проверять Terminated свойство и выходить из Execute когда оно true
Если ты сделаешь FreeOnTerminate := true - это значит, что после выхода из Execute поток сам вызовет Destroy, то есть такому потоку-классу НЕ НУЖНО делать Free / Destroy.
Если тебе нужно дождаться завершения работы потока - смотри функции WaitForSingleObject / WaitForMultipleObjects, или уже реализованный метод TThread.WaitFor
Поэтому если смотреть твой пример [30], то при классе со свойством: FreeOnTerminate := true - правильный сценарий 3.
При FreeOnTerminate := false правилен такой сценарий:MyThread.Terminate;
MyThread.WaitFor;
MyThread.Free ;
Косяк может быть действительно в том, когда вызывается код из секции finalization. Я в библиотеках им не пользуюсь. Используй стандартные посылки Windows. То есть:library DllEntry;
procedure DLLEntryPoint(Reason: DWORD);
begin
case Reason:
Dll_Process_Attach: ДЕЛАЕМ ИНИЦИАЛИЗАЦИЮ БИБЛИОТЕКИ
DLL_PROCESS_DETACH: ДЕЛАЕМ ФИНАЛИЗАЦИЮ ВСЕХ ДАННЫХ БИБЛИОТЕКИ
end;
end;
// Здесь реализация экспортируемых функций
// экспорт
begin
if DllProc = nil then
begin
DllProc := @DLLEntryPoint;
DllEntryPoint(Dll_Process_Attach);
end;
end.
← →
Сергей М. © (2008-04-25 16:23) [45]
> Пробегал2
> Косяк может быть действительно в том, когда вызывается код
> из секции finalization. Я в библиотеках им не пользуюсь
Пользоваться или не пользоваться - это твое право.
Но косяк с дедлоком будет в любом случае.
← →
Сергей М. © (2008-04-25 16:25) [46]
> Пробегал2... (25.04.08 15:59) [44]
> если смотреть твой пример [30], то при классе со свойством:
> FreeOnTerminate := true - правильный сценарий 3
Неправильный он, как и все остальные сценарии.
← →
Пробегал2... (2008-04-25 16:33) [47]Сергей М. © (25.04.08 16:23) [45]
Но косяк с дедлоком будет в любом случае
где ты там видишь дедлок?! Словами можешь описать?
← →
Loginov Dmitry © (2008-04-25 16:35) [48]
> Признаком фактического завершения поточной функции является
> либо вызов ф-ции ExitThread() либо вызов машинструкции RET
> верхнего уровня вложенности.
Вызов <> признаку!
> тебе что нужно? Завершить поток? Так сделай ему Terminate,
> поток должен своевременно проверять Terminated свойство
> и выходить из Execute когда оно true
>
> Если ты сделаешь FreeOnTerminate := true - это значит, что
> после выхода из Execute поток сам вызовет Destroy, то есть
> такому потоку-классу НЕ НУЖНО делать Free / Destroy.
>
> Если тебе нужно дождаться завершения работы потока - смотри
> функции WaitForSingleObject / WaitForMultipleObjects, или
> уже реализованный метод TThread.WaitFor
>
> Поэтому если смотреть твой пример [30], то при классе со
> свойством: FreeOnTerminate := true - правильный сценарий
> 3.
фигня какая-то получается. Я с [0] поста доказываю, что в finalization DLL-библиотеки все это не работает, а вы все-равно внушаете, что так правильно. Да, так правильно! Но не работает!
Все-таки, я все больше прихожу к выводу, что нужна дополнительная экспортируемая функция. С вариантом, когда Винда при выгрузке DLL срубает потоки еще до finalization, достаточно сложно что-либо другое придумать.
Ведь такое обращения Windows с потоками - опасно и чревато потерей данных...
← →
jack128_ (2008-04-25 16:41) [49]
> Словами можешь описать?
На меня снижа шло озарение и я понял в чем главная проблема нашего мира. Мы не слышам друг друга...
PS
[7]
← →
Сергей М. © (2008-04-25 16:42) [50]
> Пробегал2... (25.04.08 16:33) [47]
см. [7], там как раз объяснение "словами".
← →
Сергей М. © (2008-04-25 16:53) [51]
> Loginov Dmitry © (25.04.08 16:35) [48]
> Вызов <> признаку!
Поправлюсь - не сам вызов, а результат его исполнения.
В результате исполнения вызова ExitThread или возврата по RET управление будет передано в kernel32 и никогда более не будет передано коду поточной функции, что дает все основания для беспроблемной деаллокации участка ВАП, в котором размещался машкод поточной ф-ции.
← →
Сергей М. © (2008-04-25 17:04) [52]В дополнение к [51] - подразумевается, что код поточной ф-ции м.б. смело удален из ВАП процесса не ранее чем завершат свое выполнение все потоки, созданные ранее с указанием этой поточной функции.
← →
Пробегал2... (2008-04-25 17:14) [53]Loginov Dmitry © (25.04.08 16:35) [48]
Я с [0] поста доказываю, что в finalization DLL-библиотеки все это не работает, а вы все-равно внушаете, что так правильно
как выяснили, в finalization это действительно не работает. Поэтому не надо этот код писать в finalization. ГДЕ НУЖНО ПИСАТЬ этот код - я написал в посте [44]
jack128_ (25.04.08 16:41) [49]
На меня снижа шло озарение и я понял в чем главная проблема нашего мира. Мы не слышам друг друга...
PS
[7]
теперь понял! Честное слово, почему-то пропустил пост [7], не читал его... Да, наверное так и есть.
← →
Сергей М. © (2008-04-25 17:20) [54]
> Пробегал2... (25.04.08 17:14) [53]
> не надо этот код писать в finalization. ГДЕ НУЖНО ПИСАТЬ
> этот код - я написал в посте [44]
Финализация юнитов вызвается в контексте вызванной DllMain(DLL_PROCESS_DETACH), так что без разницы, где будет вызвана wait-функция ожидания завершения потока - хоть непосредственно в DllMain, хоть в finalization. Результат будет один и тот же - "не дождетесь !")
← →
Loginov Dmitry © (2008-04-25 17:29) [55]
> Финализация юнитов вызвается в контексте вызванной DllMain(DLL_PROCESS_DETACH),
> так что без разницы, где будет вызвана wait-функция ожидания
> завершения потока - хоть непосредственно в DllMain, хоть
> в finalization. Результат будет один и тот же - "не дождетесь
> !")
И это правда!
Проверено! :)
← →
Пробегал2... (2008-04-25 17:52) [56]Сергей М. © (25.04.08 17:20) [54]
странно... даже как-то бредово... А где же тогда рекомендуется завершать потоки, созданные в DLL? Ведь идеологически при DLL_PROCESS_DETACH самое место...
Ну тогда я вижу один извращенный вариант, других по-моему просто нет.TMyThread = class(TThread)
private
FFinallyEvent: Thandle ;
protected
procedure execute; override;
constructor Create;
destructor Destroy;
property FinallyEvent: Thandle read FFinallyEvent;
end;
....
constructor TMyThread.Create;
begin
FFinallyEvent := CreateEvent(bla bla не помню что там надо) ;
FreeOnTerminate := true ;
ResetEvent(FFinallyEvent);
inherited Create(false) ;
end;
destructor TMyThread.Destroy;
begin
CloseHandle(FFinallyEvent);
inherited;
end;
procedure TMyThread.Execute;
begin
while not terminate
РАБОТАЕМ
SetEvent(FFinallyEvent) ;
end;
Соответственно, вызовы приблизительно такие:var
MyThread: TMyThread;
...
initialization
MyThread := TMyThread.Create;
finalization
MyThread.Terminate;
WaitForSingleObject(MyThread.FinallyEvent) ;
end.
впрочем, как я понимаю, код с FFinallyEvent можно и убрать. Все равно событие выставляется ДО того, как фактически поток будет завершен, просто максимально приближает ожидания момента к реальному моменту уничтожения потока...
Так что можно и без event"а... Все равно судя по всему FreeLibary вернет управление, но поток будет продолжать крутиться и ВАП не будет очищено, то есть вс в порядке, в результате все равно все финализируется и беспокоится нечего.
event можно использовать только как знак, что поток уже на финальной стадии завершения, то есть он уже не будет ничего никуда передавать, не будет ничего создавать и открывать и прочее...
← →
Loginov Dmitry © (2008-04-25 18:06) [57]
> Пробегал2... (25.04.08 17:52) [56]
Практически тот же изврат, что и при while Assigned(MyThread) do...
но более правильный.
От срубания потоков виндой все-равно не спасет! :)
← →
Пробегал2... (2008-04-25 18:12) [58]Loginov Dmitry © (25.04.08 18:06) [57]
Практически тот же изврат, что и при while Assigned(MyThread) do...
но более правильный
ну нифига... У тебя все расчитано, что максимум будет создан один поток.. Второй поток уже внесет несусветную суматоху. У меня же поток по всем правилам ООП написан ;) Поменяются тольуо функции ожидания для нескольких потоков, будет использована WaitForMultipleObjects
Loginov Dmitry © (25.04.08 18:06) [57]
От срубания потоков виндой все-равно не спасет! :)
да с чего ты взял, что винда потоки срубает?!?! Винда финализирует потоки не при FreeLibrary, а при завершении процесса, тогда она все ресурсы пытается освободить, созданные этим процессом.
← →
Игорь Шевченко © (2008-04-25 19:05) [59]
> странно... даже как-то бредово... А где же тогда рекомендуется
> завершать потоки, созданные в DLL? Ведь идеологически при
> DLL_PROCESS_DETACH самое место...
потоки не создаются в DLL. Потоки создаются в процессе. Познай эту истину и будет тебе рулез вечный и немеряный
← →
Пробегал2... (2008-04-25 19:18) [60]Игорь Шевченко © (25.04.08 19:05) [59]
потоки не создаются в DLL. Потоки создаются в процессе
а вам доставляет удовольствие цепляться к словам? Любопытно посто.
Если действительно непонятна фраза "потоки созданные в DLL" - я уточню. Это потоки, которые созданы в том месте маш. кода, который был загружен в ВАП процесса при проецировании образа DLL.
К чему еще изволите придраться?
← →
Игорь Шевченко © (2008-04-25 19:23) [61]Пробегал2... (25.04.08 19:18) [60]
И чем они отличаются от потоков, созданных в другом месте кода ?
← →
Сергей М, (2008-04-25 19:30) [62]
> Пробегал2... (25.04.08 19:18) [60]
> Это потоки, которые созданы в том месте маш. кода, который
> был загружен в ВАП процесса при проецировании образа DLL
Не нало месить кислое и фиолетовое.
← →
Пробегал2... (2008-04-25 20:35) [63]Игорь Шевченко © (25.04.08 19:23) [61]
И чем они отличаются от потоков, созданных в другом месте кода ?
тем, что потоки созданные в DLL должны уничтожаться также в DLL. Это логичная методика работы.
DLL как черный ящик, она экспортирует нужный мне функционал, а как она его реализовывает - мне все равно. И то что создано в DLL - внутри нее же и должно быть финализировано.
С таким же успехом и глобальные переменные, выделенные в DLL - можно очищать в самом приложении, не так ли? Только это нелогично, это - неудобно.
Плюс весь WinApi спроектирован таким образом и я думаю стоит придерживаться этого подхода. Когда вам требуется принять некую структуру данных - ВЫ выделяете память под нее и передаете на нее ссылку, по которой эта структура заполняется библиотекой.
Заметьте, не библиотека выделяет память и передает ссылку на заполненную структуру, которую ВЫ потом должны уничтожить.
Принцип один: если намусорил - подчисти за СОБОЙ.
И если там какая-то DLL создала поток для реализации функционала - она же этот поток и должна уничтожить. Имхо, если DLL хорошо спроектирована - то я в любое время могу вызывать FreeLibrary - и DLL должна очистить все ресурсы, занятые ею в процессе работы и вернуть все в то состояние, которое было до вызова LoadLibrary.
← →
Игорь Шевченко © (2008-04-25 20:42) [64]Пробегал2... (25.04.08 20:35) [63]
Это всего лишь твое имхо. Ни больше, ни меньше.
В системе и в приложениях есть примеры и одного подхода, и другого, не надо выдавать свое имхо за абсолютную истину, а главное, делать из этого имха какие-то глобальные выводы.
← →
Сергей М, (2008-04-25 20:43) [65]Удалено модератором
← →
Сергей М, (2008-04-25 21:00) [66]Здесь
http://msdn2.microsoft.com/en-us/library/ms885202.aspx
черным по белому нарисована логика вызовов DllMain с тем или иным резоном.
С учетом же того, что вызовы DllMain конкретного модуля в контексте текущего процесса осуществляются системой синхронно, "феномен зависания" становится совершенно очевидным и понятным, даже без вникания во всякие там PEBы и TIBы.
← →
Сергей М, (2008-04-25 21:01) [67]))
← →
Loginov Dmitry © (2008-04-25 21:12) [68]> ну нифига... У тебя все расчитано, что максимум будет создан
> один поток.. Второй поток уже внесет несусветную суматоху.
мне просто не требуется, чтобы в программе крутилось несколько однотипных потоков, поэтому выбрано такое решение. В других случаях будет выбрано другое решение. Кстати, после WaitForSingleObject() стоило бы выждать хотябы немного времени (например 50 / 100 мс), чтобы стать более уверенным, что функция потока уперлась в ExitThread() (а этот код уже выполняется не в нашей DLL-ке, а в kernel) и ожидает снятия блокировки, в этом случае выгрузка библиотеки уже точно ни на что не повлияет, и никаких AV не будет.
> да с чего ты взял, что винда потоки срубает?!?! Винда финализирует
> потоки не при FreeLibrary
Вот срубает и все тут. Причем FreeLibrary() перед закрытием программы вызывается. В одном случае срубает, в другом - не срубает. Есть конечно подозрение, что где-то в системе лишний раз LoadLibrary() для моей библиотеки кто-то вызвал, но наврядли... Проверю на следующей неделе.
> И чем они отличаются от потоков, созданных в другом месте
> кода ?
Потоковой функцией, код которой выгружается вместе с DLL-кой в том случае, если он принадлежит DLL-ке.
← →
Пробегал2... (2008-04-25 21:42) [69]Игорь Шевченко © (25.04.08 20:42) [64]
Это всего лишь твое имхо. Ни больше, ни меньше
ок, давайте по другому. Игорь, только честно - у вас были проекты, где поток создавался в коде DLL, а завершался в другом месте?
P.S. Это я уже не говорю об использовании класса TThread, там уж как ни крути финализировать надо там же, где создаешь.
← →
Игорь Шевченко © (2008-04-25 22:50) [70]Пробегал2... (25.04.08 21:42) [69]
Я не единственный разработчик программного обеспечения на этом свете.
И на слабо бери кого-нибудь другого.
← →
Пробегал2... (2008-04-25 23:40) [71]Игорь Шевченко © (25.04.08 22:50) [70]
как я понимаю, ответ нет, ни в одном проекте вы так не делали.
Что и требовалось доказать.
← →
Игорь Шевченко © (2008-04-26 00:13) [72]Пробегал2... (25.04.08 23:40) [71]
И на слабо бери кого-нибудь другого. Доказатель фигов
← →
Пробегал2... (2008-04-26 02:52) [73]ну хорошо. Я моих проектах никогда не было, чтобы поток создавался в DLL, а завершался в другой DLL или в самом приложении.
И мне такой подход кажется нелогичным и путанным, когда DLL обязывает выполнять какие-то телодвижения кроме загрузки и выгрузки библиотеки.
Да, это мое ИМХО. ну не согласны - и не согласны ;)
← →
Игорь Шевченко © (2008-04-26 11:02) [74]Пробегал2... (26.04.08 02:52) [73]
С точки зрения процесса, и основное приложения и DLL - это всего лишь части кода, связанные в единое адресное пространство (про различные менеджеры памяти или VMT для дельфийских классов в этом аксепте упоминать сейчас не будем, так как консепция потоков не зависит от используемого языка программирования). Таким образом, ничто не мешает потоку, начавшись в одной части кода. завершится абсолютно в другой.
Система это делать позволяет.
Более того, система даже позволяет создать поток в одном приложении, а завершать его в другом, используя функции CreateRemoteThread и TerminateThread
Давайте все-таки различать - возможно/невозможно и удобно/неудобно
← →
Котик Б (2008-04-26 16:48) [75]Игорь, я Вами восхищаюсь :)
← →
имя (2008-04-26 20:28) [76]Удалено модератором
← →
Экс-Оригинал (2008-04-26 21:59) [77]Кто-нибудь может привести пример(свой, чужой - неважно),
где бы в DLL создавался поток (BeginThread/TThread), затем DLL из приложения выгружалась бы, а поток продолжал работать?
← →
Loginov Dmitry © (2008-04-26 22:08) [78]> где бы в DLL создавался поток (BeginThread/TThread), затем
> DLL из приложения выгружалась бы, а поток продолжал работать?
На ум приходит только одно: потоковая функция расположена в другом модуле.
← →
guav © (2008-04-26 22:22) [79]
> > где бы в DLL создавался поток (BeginThread/TThread), затем
> > DLL из приложения выгружалась бы, а поток продолжал работать?
> На ум приходит только одно: потоковая функция расположена
> в другом модуле.
Потоковая это только адрес начала потока, далее может быть переходы куда угодно. Легко представить себе начало потока в dll, затем продолжение в другой и вызов ExitThread уже оттуда. Можно даже и без ExitThread, обычным возвратом, просто переход в другой модуль не по call, а по jmp.
Или так: в потоке создаются фиберы, и поток завершается в фибере созданном в другом модуле.
← →
Экс-Оригинал (2008-04-26 22:53) [80]
> На ум приходит только одно: потоковая функция расположена
> в другом модуле.
т.е.?
Страницы: 1 2 3 вся ветка
Форум: "Прочее";
Текущий архив: 2008.06.08;
Скачать: [xml.tar.bz2];
Память: 0.64 MB
Время: 0.053 c