Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2011.03.27;
Скачать: [xml.tar.bz2];

Вниз

Как проверить успешно ли начался "процесс" в другом потоке?   Найти похожие ветки 

 
Ruzzz   (2009-08-21 02:29) [0]

В отдельном потоке создаю слушающий сокет, хотелось бы чтобы функция, которая запускает этот поток могла вернуть True/False в зависимости от успешности Bind(Host, Port) этого слушающего сокета. Сейчас использую таймер, проверяющий свойство класса потока, которое устанавливается в Execute. Но мне не нравится это решение. Создавать сокет в главном потоке тоже не хочется, пишу код без привязки к конкретной реализации сокетов, вдруг какая-либо "сокетная" библиотека будет зависеть от этого, например использовать очередь потока. Помогите решить!

Поместил не в "Сети", потому что показалось что вопрос больше не в сетях, а в потоках :)


 
Германн ©   (2009-08-21 02:36) [1]


> Ruzzz   (21.08.09 02:29)
>
> В отдельном потоке создаю слушающий сокет, хотелось бы чтобы
> функция, которая запускает этот поток могла вернуть True/False
> в зависимости от успешности Bind(Host, Port) этого слушающего
> сокета.

А зачем это нужно?


 
Ruzzz   (2009-08-21 02:58) [2]

Для связи с GUI, если порт занят, то сразу же скажем об этом


 
Ruzzz   (2009-08-21 03:07) [3]

Есть свойство OnChangeActive у класса реализующего сервер, и есть метод Start, этот метод создает поток, который в свою очередь создает слушающий сокет. Также в Start после создания "слушающего" потока идет вызов OnChangeActive, для того чтобы реагировало GUI. OnChangeActive также вызывается и в методе Stop :)

Но вот сейчас думаю, что правильней будет вызывать OnChangeActive из потока через Synchronize :) Ох не варит голова


 
Ruzzz   (2009-08-21 04:39) [4]

Я наверное создаю велосипед, но ничего не смог найти :( Короче одни проблемы. Если при завершении потока вызывать через Synchronize метод который будет делать OnChangeActive, то появляется проблема, если я в методе Stop делаю так:
 if Active then begin
   FListenThread.Terminate;
   WaitForSingleObject(FListenThread.Handle, INFINITE); // Похоже здесь deadlock
 end;


 
Вариант   (2009-08-21 07:43) [5]

Для сигнализации в поток окна  о том, что действие в другом потоке было выполнено успешно или неуспешно, вполне можно использовать 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 анализом возвращаемого функцией результата.


 
Сергей М. ©   (2009-08-21 08:29) [6]


> Создавать сокет в главном потоке тоже не хочется, пишу код
> без привязки к конкретной реализации сокетов


Не видно взаимосвязи между реализацией сокетов и потоком, в котором вызываются функции этой реализации.

По-моему, ты усложнаешь себе жизнь.
Метод Start, реализованный в твоем классе и будучи вызванный откуда бы то ни было в каком бы то ни было потоке, преспокойно создает гнездо (1), биндит его (2) и, если надо, делает слушающим (3), после чего создает слушающий поток (4), передавая тому параметром хэндл этого гнезда.
На любом шаге из последовательности 1,2,3 может возникнуть отказ (в т.ч. и по причине занятости порта на этапе 2), о чем метод Start немедленно узнает и немедленно же прекращает последовательность, не доводя ее до шага 4 и немедленно же возвращая управление вызвавшему его коду, сообщая о результатах старта сервера требуемым от метода образом.


 
Leonid Troyanovsky ©   (2009-08-21 09:06) [7]


> Вариант   (21.08.09 07:43) [5]

> Советую сигналить - PostMessage

Такой вызов сделает из потока GUI thread.
Cигналить можно, например, посылкой QueueUserAPC потоку,
находящемуся в Wait..Ex.

--
Regards, LVT.


 
Ruzzz   (2009-08-21 09:09) [8]

Вариант, спасибо за развернутый ответ. Да INFINITE это я зря делал. По поводу блокирующих операций думаю хранить список хендлов сокетов и закрывать их, а поток уже пусть отрабатывает до конца, но следит за ошибками сокетов. Хотя с другой стороны у меня не должно быть долгих операций с сокетами, и таймауты не большие, хотелось бы что бы сокеты не закрывались принудительно, а отрабатывали до конца даже в случае закрытия приложения, я поэтому и ставил INFINITE. Но тут буду еще все хорошо прорабатывать.

По поводу своего главного вопроса ) все же решил вместо сигналить PostMessage, создавать сокет и делать bind в главном потоке, а "слушающий" поток пусть уже слушает и делает accept. Поэтому такой вопрос, чем это чревато?

Вообще логика такая, поток должен отработать нормально, то есть его убивать плохая практика, закрыться он должен только по сигналу. Его работа это слушать в цикле. Слушающий сокет система никогда не закроет. К чему это я, к тому что из потока мы выйдем только если подадим сигнал, а значит мы всегда будем уверены работает сервер или нет, то есть дали команду start, значит работает, stop значит нет. Но тут появляется проблема, как обработать ошибку бинда? Если все хорошо то поток работает - тут проблем нет, тут и Synchronize подойдет, а если бинд с ошибкой, то выходим из потока (вот и плохая ситуация когда поток завершается не по нашей команде) и что дальше? Следить за тем работает ли поток, но как? Посылать сообщения, тогда должна быть очередь, в главном потоке VCL не проблема, но все же не то ). Метод Synchronize (OnTerminate это тоже самое) в конце функции потока чреват deadlock"ом, потому что после команды стоп(т.е. уже в другой ситуауции, когда поток завершается не из-за ошибки бинда а по нашему сигналу), нам желательно подождать его (в том числе чтобы и диструкторы отработали при закрытии приложения). Вообщем проверка этого бинда все портит. Буду делать бинд в основном потоке.

У меня такое чувство что все это давно разжевано, да я все пропустил :(


 
Ruzzz   (2009-08-21 09:16) [9]

Сергей М. , Leonid Troyanovsky , не увидел ваши сообщения :) да именно как вы говорите Сергей М., так и буду делать, так вообщем то и делал, но видать нехватка знания заставила засомневаться, а не будут ли проблемы, спс за ответы, иногда вроде знаешь как сделать, но нужно чтобы кто-то разжевал :)


 
Сергей М. ©   (2009-08-21 09:18) [10]


> чем это чревато?


Ничем абсолютно.


> создавать сокет и делать bind в главном потоке


Причем тут главный или неглавный ?
В потоке, вызывающем, методы твоего класса !


 
Ruzzz   (2009-08-21 09:40) [11]

> В потоке, вызывающем, методы твоего класса !
Да имено так, еще раз спасибо! То что вы исправляете меня так, говорит о том что хорошо поняли мою ситуацию ), а значит совет:
>Ничем абсолютно.
Принимаю как руководство к действию )


 
Вариант   (2009-08-21 11:16) [12]


> Leonid Troyanovsky ©   (21.08.09 09:06) [7]


> Такой вызов сделает из потока GUI thread.

Есть два вопроса
- сделает GUI thread - если можно -что это означает для потока вызвашего PostMessage, для посылки сообщения например главному окну? user32?
И второй вопрос - Это плохо? Borland до дельфи 5 включительно для  Synchronize использовал SendMessage. И если это сделает GUI Thread -  мне кажется это допустимо, ибо другие варианты сложнее для реализации, хотя и возможны. Но с интересом бы выслушал аргументацию или просмотрел статью(обсуждение) по ссылке.


 
Leonid Troyanovsky ©   (2009-08-21 13:39) [13]


> Вариант   (21.08.09 11:16) [12]

> - сделает GUI thread - если можно -что это означает для
> потока вызвашего PostMessage, для посылки сообщения например
> главному окну? user32?

В изначально созданном потоке нет a thread"s message queue,
она создается при первом обращении к User or GDI функциям.
Думаю, что это не одна структура, отличающая GUI поток
от work thread, если, например, вспомнить, что окна, хуки,
таблицы акселераторов  являются собственностью потока,
и, сл-но, их описания  где-то в ем (объекте ядра) хранятся.

> И второй вопрос - Это плохо? Borland до дельфи 5 включительно
> для  Synchronize использовал SendMessage. И если это сделает
> GUI Thread -  мне кажется это допустимо, ибо другие варианты
> сложнее для реализации

Не знаю, плохо или нет.
Для рабочего потока (рабочей лошадки) все это илишества.

Насчет SendMessage - они переделали лишь потому, что
в некоторых случаях он приводил к deadlock.
Ну, и еще, наверное, что целились в линукс.

Сложность реализации борланды сами задали кривизной TApplication
(впрочем, и нек. других классов, скажем, TScreen и т.д.), например,
в районе Idle. Если б можно было возможность всунуть туда вместо
WaitMessage тот же MsgWaitForMultipleObjectsEx оно б пошло
приложению только на пользу.

--
Regards, LVT.


 
Вариант   (2009-08-21 14:16) [14]


> Если б можно было возможность всунуть туда вместо
> WaitMessage тот же MsgWaitForMultipleObjectsEx оно б пошло
> приложению только на пользу


MsgWaitForMultipleObjectsEx  - возможность то есть в своем коде это сделать, только код это несколько усложняет (хотя и не сильно, но выглядит немного извращением) и есть еще одно для меня

> Для рабочего потока (рабочей лошадки) все это илишества.
 -  тут спорить не буду - есть такое, но просто мне нравится простой способ сигнализации с возможностью передачи и дополнительных параметров - это я о PostMessage или о PostThreadMessage.
Спасибо за ответ.


 
Ruzzz   (2009-08-22 18:37) [15]

Leonid Troyanovsky, не могли бы ткнуть ссылкой где подробнее узнать о «PostMessage - Такой вызов сделает из потока GUI thread.»?

Вот у Рихтера нашел (стр 649-650), GUI поток имеет дополнительно THREADINFO тут есть очереди сообщений, PostMessage - это ассинх. посылка и не возвращает результат обработки сообщения оконной функцией (возвращает только True/False - успешность операции). Поэтому после ее выполнения, потоку не нужно создавать очередь ответных сообщений? Так или нет? То есть по идее PostMessage не делает GUI thread?


 
Ruzzz   (2009-08-22 18:41) [16]

Да и у того же Рихтера говорится, что из рабочего в GUI поток «превращается» только после создания окна.


 
VladimirVB   (2009-08-22 18:45) [17]

При помощи функции WaitForSingleObject

Попробуй такой пример

program Project1;

{$APPTYPE CONSOLE}

uses
 SysUtils,
 Windows;

var
 hThread: HWND;
 IDThread: DWORD;

procedure thread; stdcall;
var
 i: Integer;
begin
 for i := 0 to 9 do
 begin
   Write(i, " ");
   Sleep(100);
 end;
 Writeln;
end;

begin
 hThread := CreateThread(nil, 0, @thread, nil, 0, IDThread);
 if hThread = 0 then
   Halt(GetLastError);

 // ждем завершения потока thread
 if WaitForSingleObject(hThread, INFINITE) <> WAIT_OBJECT_0 then
 begin
   Writeln("Wait for single object failed.");
   Writeln("Press any key to exit.");
   Readln;
 end;

 //закрываем дескриптор потока
 CloseHandle(hThread);
 Write("Press any key to exit.");
 Readln;
end.


 
Сергей М. ©   (2009-08-22 18:51) [18]


> VladimirVB   (22.08.09 18:45) [17]


Сейчас тебя поколотят за:

1. Пример, не имеющий отношения к проблеме автора.
2. Пример, ведущий к заблуждениям в отношении CreateThread vs BeginThread


 
Ruzzz   (2009-08-22 18:56) [19]

поспешил :) нашел вот еще: http://pic.ipicture.ru/uploads/090822/CH0Y5ps7U8.jpg - осталось узнать список этих самых функций


 
Сергей М. ©   (2009-08-22 22:28) [20]


> узнать список этих самых функций


Достаточно двух - GetMessage и PeekMessage


 
Leonid Troyanovsky ©   (2009-08-24 07:33) [21]


> Ruzzz   (22.08.09 18:37) [15]

> Leonid Troyanovsky, не могли бы ткнуть ссылкой где подробнее
> узнать о «PostMessage - Такой вызов сделает из потока GUI

http://msdn.microsoft.com/en-us/library/ms644946(VS.85).aspx

The system creates a thread"s message queue when the thread makes its first
call to one of the User or GDI functions.

> Ruzzz   (22.08.09 18:56) [19]
> jpg - осталось узнать список этих самых функций

Можно посмотреть импорты user32.dll & gdi32.dll путем tdump.exe

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2009-08-24 07:42) [22]


> Сергей М. ©   (22.08.09 18:51) [18]

> Сейчас тебя поколотят за:

3. procedure thread; stdcall;

> VladimirVB   (22.08.09 18:45) [17]

function ThreadProc(lpParameter: Pointer): DWORD; stdcall;

Кста, Write/Ln - потоконебезопасная функция.

--
Regards, LVT.


 
Ruzzz   (2009-08-24 20:31) [23]

Я так и не нашел где написано, что поток КОТОРЫЙ ВЫЗЫВАЕТ PostMessage или PostThreadMessage (т.е. функции не требующих очередь возвращенных результатов) становится GUI-потокам.


 
Leonid Troyanovsky ©   (2009-08-24 22:17) [24]


> Ruzzz   (24.08.09 20:31) [23]

> Я так и не нашел где написано

[21]

Кхм.. PostMessage или PostThreadMessage
Minimum DLL Version user32.dll

--
Regards, LVT.


 
Ruzzz   (2009-08-24 22:57) [25]

Leonid Troyanovsky :) ну хорошо, т.е. можно точно утверждать что все функции из user32.dll & gdi32.dll создают из потока - GUI-поток? Просто мне кажется что это бессмысленно для PostMessage или PostThreadMessage, поток вызывающий эти функции вполне может быть и не GUI-поток. Или я не прав?


 
Leonid Troyanovsky ©   (2009-08-25 08:55) [26]


> Ruzzz   (24.08.09 22:57) [25]

> Leonid Troyanovsky :) ну хорошо, т.е. можно точно утверждать
> что все функции из user32.dll & gdi32.dll создают из потока
> - GUI-поток?

Насчет всех зуб не дам, бо есть, например, такая функция:

function IsGUIThread(bConvert: BOOL):BOOL; stdcall;
 external user32 name "IsGUIThread";

которая осуществляет превращение лишь по требованию.

> Просто мне кажется что это бессмысленно для PostMessage
> или PostThreadMessage, поток вызывающий эти функции вполне
> может быть и не GUI-поток. Или я не прав?

Поставим смелый эксперимент:

type
  TMyThread = class (TThread)
  public
    procedure Execute; override;
  end;

procedure TMyThread.Execute;
begin
 // IsGUIThread(True);
 // PostThreadMessage(MainThreadId, WM_NULL, 0, 0);
 // PostMessage(Application.MainForm.Handle, WM_NULL, 0, 0);
 if IsGUIThread(False) then
   MessageBox(0, "GUI", "GUI or not GUI", 0);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 TMythread.Create(False);
end;

И.. о чудо!
Легким движение руки шорты превращаются .. в элегантные брюки.

Насчет смысла можно сказать, что, например, для SendMessage
потоку уж точно потребуется очередь.

--
Regards, LVT.


 
Ruzzz   (2009-08-25 09:57) [27]

Спасибо за пример! У меня в результате запуска кода с закомментированными строками, поток оказывается GUI-потоком. Т.е. получается что если использовать класс TThread, то Delphi создает GUI-поток чтоли? Обрыл TThread, вроде ничего не нашел. Чудеса )

Но даже такой код:
function ThreadFunc(Parameter: Pointer): DWORD; cdecl;
begin
 if IsGUIThread(True) then MessageBox(0, "GUI", "GUI or not GUI", 0);
end;

procedure TForm3.Button3Click(Sender: TObject);
var
 lpThreadId: DWORD;
begin
 CreateThread(nil, 0, @ThreadFunc, nil, 0, lpThreadId);
end;

Говорит что это GUI-поток. Странно это :)


 
Ruzzz   (2009-08-25 10:05) [28]

Ошибся, нужно IsGUIThread(False), но результат не изменился  :)
http://pic.ipicture.ru/uploads/090825/RvrQ5ES4Pv.png


 
Leonid Troyanovsky ©   (2009-08-25 10:20) [29]


> Ruzzz   (25.08.09 09:57) [27]

> что если использовать класс TThread, то Delphi создает GUI-
> поток чтоли? Обрыл TThread, вроде ничего не нашел. Чудеса

IsGUIThread начиная с XP.
А дельфи какая?

Кста, не cdecl but stdcall.

--
Regards, LVT.


 
Ruzzz   (2009-08-25 17:33) [30]

Turbo Delphi, Win XP SP3, IsGUIThread(False) - всегда выдает что это GUI-поток


 
Leonid Troyanovsky ©   (2009-08-25 18:20) [31]


> Ruzzz   (25.08.09 17:33) [30]

> Turbo Delphi, Win XP SP3

Да, на XP SP3 у меня тоже IsGUIThread всегда True (as 0x1).
Видимо, ms накосячили в XP, бо на 2003 server она работает.
Пробовал на D6.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2009-08-25 18:44) [32]


> Ruzzz   (25.08.09 17:33) [30]

Гм.. Пришлось добывать доказательства для PostMessage другим путем:

type
 TMyThread = class (TThread)
 public
   e: THandle;
   procedure Execute; override;
 end;

procedure TMyThread.Execute;
begin
// PostThreadMessage(MainThreadId, 0, 0, 0);
// PostMessage(Application.MainForm.Handle, 0, 0, 0);
SetEvent(e);
Sleep(10000);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
with TMythread.Create(True) do
  begin
    e := CreateEvent(nil, False, False, nil);
    Resume;
    WaitForSingleObject(e, INFINITE);
    Win32Check(PostThreadMessage(ThreadId, WM_NULL, 0, 0));
    Free;
  end;
end;


---------------------------
Debugger Exception Notification
---------------------------
Project Project1.exe raised exception class EOSError with message "System Error.  Code: 1444.
Неверный идентификатор потока команд". Process stopped. Use Step or Run to continue.
---------------------------
OK   Help  
---------------------------

Но, IsGUIThread(True), сволочь, не работает в XP, похоже просто заглушка.

--
Regards, LVT.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2011.03.27;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.006 c
15-1292196119
semjuel
2010-12-13 02:21
2011.03.27
Нужен компонент.....


1-1249326627
TStas
2009-08-03 23:10
2011.03.27
Заставка программы не перерисовывается, как нужно


3-1255361880
Piter
2009-10-12 19:38
2011.03.27
Оптимизация Join а в Postgres


10-1172572882
and&amp;
2007-02-27 13:41
2011.03.27
связать две Active Form


3-1255946557
Ulugbek
2009-10-19 14:02
2011.03.27
Помогите оптимизировать View .. Firebird 2





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