![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как проверить успешно ли начался "процесс" в другом потоке? [WinXP]
Ruzzz © (2009-08-21 02:29:00)В отдельном потоке создаю слушающий сокет, хотелось бы чтобы функция, которая запускает этот поток могла вернуть True/False в зависимости от успешности Bind(Host, Port) этого слушающего сокета. Сейчас использую таймер, проверяющий свойство класса потока, которое устанавливается в Execute. Но мне не нравится это решение. Создавать сокет в главном потоке тоже не хочется, пишу код без привязки к конкретной реализации сокетов, вдруг какая-либо "сокетная" библиотека будет зависеть от этого, например использовать очередь потока. Помогите решить!
Поместил не в "Сети", потому что показалось что вопрос больше не в сетях, а в потоках :)
Вариант (2009-08-21 11:16:00) [21]
> Leonid Troyanovsky © (21.08.09 09:06) [7]
> Такой вызов сделает из потока GUI thread.
Есть два вопроса
- сделает GUI thread - если можно -что это означает для потока вызвашего PostMessage, для посылки сообщения например главному окну? user32?
И второй вопрос - Это плохо? Borland до дельфи 5 включительно для Synchronize использовал SendMessage. И если это сделает GUI Thread - мне кажется это допустимо, ибо другие варианты сложнее для реализации, хотя и возможны. Но с интересом бы выслушал аргументацию или просмотрел статью(обсуждение) по ссылке.
Ruzzz (2009-08-21 09:40:00) [22]> В потоке, вызывающем, методы твоего класса !
Да имено так, еще раз спасибо! То что вы исправляете меня так, говорит о том что хорошо поняли мою ситуацию ), а значит совет:
>Ничем абсолютно.
Принимаю как руководство к действию )
Сергей М. (2009-08-21 09:18:00) [23]
> чем это чревато?
Ничем абсолютно.
> создавать сокет и делать bind в главном потоке
Причем тут главный или неглавный ?
В потоке, вызывающем, методы твоего класса !
Ruzzz (2009-08-21 09:16:00) [24]Сергей М. , Leonid Troyanovsky , не увидел ваши сообщения :) да именно как вы говорите Сергей М., так и буду делать, так вообщем то и делал, но видать нехватка знания заставила засомневаться, а не будут ли проблемы, спс за ответы, иногда вроде знаешь как сделать, но нужно чтобы кто-то разжевал :)
Ruzzz (2009-08-21 09:09:00) [25]Вариант, спасибо за развернутый ответ. Да INFINITE это я зря делал. По поводу блокирующих операций думаю хранить список хендлов сокетов и закрывать их, а поток уже пусть отрабатывает до конца, но следит за ошибками сокетов. Хотя с другой стороны у меня не должно быть долгих операций с сокетами, и таймауты не большие, хотелось бы что бы сокеты не закрывались принудительно, а отрабатывали до конца даже в случае закрытия приложения, я поэтому и ставил INFINITE. Но тут буду еще все хорошо прорабатывать.
По поводу своего главного вопроса ) все же решил вместо сигналить PostMessage, создавать сокет и делать bind в главном потоке, а "слушающий" поток пусть уже слушает и делает accept. Поэтому такой вопрос, чем это чревато?
Вообще логика такая, поток должен отработать нормально, то есть его убивать плохая практика, закрыться он должен только по сигналу. Его работа это слушать в цикле. Слушающий сокет система никогда не закроет. К чему это я, к тому что из потока мы выйдем только если подадим сигнал, а значит мы всегда будем уверены работает сервер или нет, то есть дали команду start, значит работает, stop значит нет. Но тут появляется проблема, как обработать ошибку бинда? Если все хорошо то поток работает - тут проблем нет, тут и Synchronize подойдет, а если бинд с ошибкой, то выходим из потока (вот и плохая ситуация когда поток завершается не по нашей команде) и что дальше? Следить за тем работает ли поток, но как? Посылать сообщения, тогда должна быть очередь, в главном потоке VCL не проблема, но все же не то ). Метод Synchronize (OnTerminate это тоже самое) в конце функции потока чреват deadlock'ом, потому что после команды стоп(т.е. уже в другой ситуауции, когда поток завершается не из-за ошибки бинда а по нашему сигналу), нам желательно подождать его (в том числе чтобы и диструкторы отработали при закрытии приложения). Вообщем проверка этого бинда все портит. Буду делать бинд в основном потоке.
У меня такое чувство что все это давно разжевано, да я все пропустил :(
Leonid Troyanovsky (2009-08-21 09:06:00) [26]
> Вариант (21.08.09 07:43) [5]
> Советую сигналить - PostMessage
Такой вызов сделает из потока GUI thread.
Cигналить можно, например, посылкой QueueUserAPC потоку,
находящемуся в Wait..Ex.
--
Regards, LVT.
Сергей М. (2009-08-21 08:29:00) [27]
> Создавать сокет в главном потоке тоже не хочется, пишу код
> без привязки к конкретной реализации сокетов
Не видно взаимосвязи между реализацией сокетов и потоком, в котором вызываются функции этой реализации.
По-моему, ты усложнаешь себе жизнь.
Метод Start, реализованный в твоем классе и будучи вызванный откуда бы то ни было в каком бы то ни было потоке, преспокойно создает гнездо (1), биндит его (2) и, если надо, делает слушающим (3), после чего создает слушающий поток (4), передавая тому параметром хэндл этого гнезда.
На любом шаге из последовательности 1,2,3 может возникнуть отказ (в т.ч. и по причине занятости порта на этапе 2), о чем метод Start немедленно узнает и немедленно же прекращает последовательность, не доводя ее до шага 4 и немедленно же возвращая управление вызвавшему его коду, сообщая о результатах старта сервера требуемым от метода образом.
Вариант (2009-08-21 07:43:00) [28]Для сигнализации в поток окна о том, что действие в другом потоке было выполнено успешно или неуспешно, вполне можно использовать PostMessage.
Правда в этом случае надо учитывать, что на момент обработки сообщения поток-источник сообщения уже может не существовать. Но это можно проверить.
Метод Synchronize тормозит выполнения потока до конца выполнения вызванной в нем функции(метода). Поэтому код в основном потоке
> if Active then begin
> FListenThread.Terminate;
> WaitForSingleObject(FListenThread.Handle, INFINITE);> // Похоже здесь deadlock
> end;
может привести к взаимоблокировке потоков. Так как WaitForSingleObject тормозит поток до перехода объекта в сигнальное состояние или истечения тайм-аута. В функции остановки потока я бы рекомендовал использовать WaitForSingleObject(FListenThread.Handle, Время_ожидания); - где Время_ожидания - это достаточное приемлимое время для завершения потока. Если поток не завершился за указанное время, возможно имеет смысл "убить" его (или выполнить другие действия, выбор за вами).
Или использовать функцию MsgWaitForMultipleObjects, но при вызове этой функции возможны свои ньюансы, связанные с повторным вызовом кода например, что необходимо учитывать.
И еще, в функции Stop команда на прекращении работы у тебя дается
с помощью
> FListenThread.Terminate
А если потока занят блокирующей операцией, например чтением сокета или вызов accept слушающего сокета, ожидание события и т.п. То вызов Terminate может ничего не дать. В этом случае надо бы прекратить блокирующие операции - если они есть (например закрыв сокет - если выполнялись оперции с сокетом) или могут быть другие варианты сигнализации потоку - это зависит от реализации работы потока. Просто надо учесть момент, возможности блокировки потока вызовом какой-либо функции...
Резюме:
Советую сигналить - PostMessage, в Stop делать WaitForSingleObject(FListenThread.Handle, Время_Ожидания); c анализом возвращаемого функцией результата.
Ruzzz (2009-08-21 04:39:00) [29]Я наверное создаю велосипед, но ничего не смог найти :( Короче одни проблемы. Если при завершении потока вызывать через Synchronize метод который будет делать OnChangeActive, то появляется проблема, если я в методе Stop делаю так:
if Active then begin
FListenThread.Terminate;
WaitForSingleObject(FListenThread.Handle, INFINITE); // Похоже здесь deadlock
end;
Ruzzz (2009-08-21 03:07:00) [30]Есть свойство OnChangeActive у класса реализующего сервер, и есть метод Start, этот метод создает поток, который в свою очередь создает слушающий сокет. Также в Start после создания "слушающего" потока идет вызов OnChangeActive, для того чтобы реагировало GUI. OnChangeActive также вызывается и в методе Stop :)
Но вот сейчас думаю, что правильней будет вызывать OnChangeActive из потока через Synchronize :) Ох не варит голова
Ruzzz (2009-08-21 02:58:00) [31]Для связи с GUI, если порт занят, то сразу же скажем об этом
Германн (2009-08-21 02:36:00) [32]
> Ruzzz (21.08.09 02:29)
>
> В отдельном потоке создаю слушающий сокет, хотелось бы чтобы
> функция, которая запускает этот поток могла вернуть True/False
> в зависимости от успешности Bind(Host, Port) этого слушающего
> сокета.
А зачем это нужно?