Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 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
11-1190048966
Seaniapeape
2007-09-17 21:09
2008.06.08
Нужен совет


15-1209313105
Simpson
2008-04-27 20:18
2008.06.08
Вирусы


15-1209297079
Kostafey
2008-04-27 15:51
2008.06.08
С днем рождения ! 27 апреля


2-1210945315
OLGA
2008-05-16 17:41
2008.06.08
Подскажите, пожалуйста неучу!!!!!!


15-1209129042
Ega23
2008-04-25 17:10
2008.06.08
А может так спонтанно на Чистые пруды?





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