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

Вниз

Передача сообщения из порождённого TThread в родительский сервис   Найти похожие ветки 

 
Lucefer   (2006-03-15 23:18) [0]

Создаю сервис, в котором объект TServerSocket порождает потоки для подключаемых клиентов. По окончании обработки эти потоки должны передать некую команду породившему их потоку. Когда то это было нечто вида
PostMessage(Application.MainForm.Handle,
RM_USER_LOGOUT,
Integer(DuplicateStrToPChar(strClientMessage)),
Integer(DuplicateStrToPChar(strClientID)));
-------------------------
Как это правильно сделать теперь? Желательно сделать это именно с помощью механизма сообщений, а не вызовом функции через Synchronize (сильно затормозит работу).


 
Reindeer Moss Eater ©   (2006-03-15 23:25) [1]

И в чем затруднение?
Нет Application.MainForm?

Дык создавая вторичные потоки передавай им хендл нужного окна и все.


 
Eraser ©   (2006-03-15 23:29) [2]


> Lucefer   (15.03.06 23:18)

1. Использовать событие OnTerminate класса TThread, но код этого события будет выполняться в основном потоке приложения, а не в потоке сервиса.
2. Использовать сообщения... ты сам привёл пример как это делать.
Если в сервисе нету окна, то можно организовать собственный цикл сообщений и отправлять их PostThreadMessage.
3. Передавать через переменные или поля объекта, защищая их критическими секциями или объектами синхронизации ядра.


 
Reindeer Moss Eater ©   (2006-03-15 23:33) [3]

Проще всего AllocateHWnd и метод класса сервиса в качестве оконной процедуры. Ничего не придется переделывать.


 
Lucefer   (2006-03-16 00:24) [4]

Спасибо за участие. Отвечаю по порядку.
1. Поскольку это сервис - окон нету вообще как класса. Соответственно нет оконных процедур, которые могли бы обработать сообщения.
2. Использовать OnTerminate не могу, так как потоки кэшируются, а не уничтожаются. Да и события происходят разные  - не просто процесс закончился - а закончился из-за за того что... (неправильный пароль, заблокированный IP, запрос к отсутствующим пока данным и т.д.) и параметр, например ID-клиента, IP-клиента, и т.д.
3. Использовать критические секции и всякие MREWS я уже думал. Но тогда придётся самому создавать список, добавлять туда сообщения из потоков, а из главного потока удалять элементы (что бы очередь не терялась). При этом как-то отслеживать поступление нового сообщения. На первый взгляд слишком мудрено.
4. По поводу PostThreadMessage - мне кажется это самое то, но есть несколько вопросов с которыми я пока не разобрался. А именно: (дальше текст из MSDN)

1. The thread to which the message is posted must have created a message queue, or else the call to PostThreadMessage fails.
2. The system only does marshalling for system messages (those in the range 0 to WM_USER). To send other messages (those above WM_USER) to another process, you must do custom marshalling.

Как в потоке создать этот message queue, причём так что бы он не загружал систему на 100% и не зацикливался если сообщение по каким-то причинам не придёт (тут наверное можно поставить выход при проверке на Terminate?)


 
Reindeer Moss Eater ©   (2006-03-16 00:27) [5]

Чем тебя не устроил AllocateHWnd?
Самый простой способ.


 
Lucefer   (2006-03-16 00:28) [6]

>Reindeer Moss Eater
>Проще всего AllocateHWnd и метод класса сервиса в качестве оконной процедуры.
---
Это как?

Т.е. вот у меня ServiceExecute уже осуществляет цикл
procedure TSomeService.ServiceExecute(Sender: TService);
begin
   FL.AppendLogRec("Service started");
   LoadConfig;
   FL.AppendLogRec("Config loaded");
   ServerSocket1.Port := ListenPort;
   ServerSocket1.ServerType := stThreadBlocking;
   ServerSocket1.ThreadCacheSize := 20;
   ServerSocket1.Active := True;
   while not Terminated do begin
     ServiceThread.ProcessRequests(True);
     sleep(0);
   end;
   ServerSocket1.Active := False;
   FL.AppendLogRec("Service stopped");
end;


 
Lucefer   (2006-03-16 00:37) [7]

Т,е. как я понимаю AllocateHWnd - создаст виртуальное окно.
1. Я создаю метод procedure TSomeService.FakeWndProc(var Msg: TMessage);
в котором буду обрабатывать свои сообщения (WM_USER+...)
2. на ServiceExecute получаю дескриптор этого виртуального окна AllocateHWnd и передаю его в создаваемый TThread, откуда и вызываю сообщения PostMessage.


 
Reindeer Moss Eater ©   (2006-03-16 00:38) [8]

function AllocateHWnd(Method: TWndMethod): HWND;

type TWndMethod = procedure(var Message: TMessage) of object;

Создаешь в классе сервиса метод-процедуру типа TWndMethod

Вызываешь AllocateHWnd с параметром - созданным методом. Получаешь хендл окна.
При создании вторичных потоков передаешь им этот хендл.
Ему потоки и будут постить сообщения.
Обрабатывать их будешь в созданном методе.


 
Eraser ©   (2006-03-16 00:53) [9]


> Reindeer Moss Eater ©   (16.03.06 00:27) [5]
>
> Чем тебя не устроил AllocateHWnd?
> Самый простой способ.

однако здесь опять же требуется чтобы в потоке был цикл выборки сообщений.

> Lucefer   (16.03.06 00:24) [4]


> Как в потоке создать этот message queue, причём так что
> бы он не загружал систему на 100% и не зацикливался если
> сообщение по каким-то причинам не придёт (тут наверное можно
> поставить выход при проверке на Terminate?)

например так:

   while GetMessage(Msg, 0, 0, 0) and (not Terminated) do
   begin
     if Msg.message = AM_PLAY_BACK then
     begin
        // some actions
     end;
     if Msg.message = WM_TIMER then
     begin
        // some other actions
     end;
   end;


 
Eraser ©   (2006-03-16 00:57) [10]


> Eraser ©   (16.03.06 00:53) [9]


> однако здесь опять же требуется чтобы в потоке был цикл
> выборки сообщений.

точнее обработка будет происходить в главном потоке, что не всегда хорошо.


 
Lucefer   (2006-03-16 08:30) [11]

И ещё я вот подумал - существует вероятность что сообщения в очередь не поставятся (по каким-то либо, одной винде известным причинам), а значит если я  для передачи параметра вызывал getmem - произойдёт утечка памяти, что не есть гуд.
Похоже лучше всего будет обернуть TList в критическую секцию, а из потока добалять туда новую команду и выставлять TEvent :(


 
Сергей М. ©   (2006-03-16 09:05) [12]


> существует вероятность что сообщения в очередь не поставятся


Нет такой вероятности.

Зато есть вероятность при собственной неверной организации цикла ожидания/выборки/обработки сообщений потерять это сообщение, тем самым допустив утечку из-за невыполнения соответствующего FreeMem


>  и выставлять TEvent


В любом случае потребуется цикл, ожидающий либо сообщения, либо срабатывание ивента, либо и то и другое


 
tesseract ©   (2006-03-16 10:09) [13]

А про DDE/named pipes/shared mem почему-то никто не упомянул. Хотя вроде для и предназначены


 
Сергей М. ©   (2006-03-16 10:13) [14]


> tesseract ©   (16.03.06 10:09) [13]


А не слишком ли жирно будет использовать DDE/named pipes/shared mem в контексте одного и того же процесса ?
Автор же не ведет речь об интерпроцессном взаимодействии, только  - о межпоточном инф.обмене внутри одного и того же "своего" процесса


 
Lucefer   (2006-03-16 11:22) [15]

Сделал так:

TSomeService = class(TService)
protected
   PMWinHandle :HWND;
   procedure FakeWndProc(var Msg: TMessage);
...
end;

procedure TSomeService.ServiceCreate(Sender: TObject);
begin
 PMWinHandle      := AllocateHWnd(FakeWndProc);
end;

procedure TSomeService.ServiceDestroy(Sender: TObject);
begin
 DeallocateHWnd(PMWinHandle);
end;

procedure TSomeService.ServerSocket1GetThread(Sender: TObject;
 ClientSocket: TServerClientWinSocket;
 var SocketThread: TServerClientThread);
begin
 //Передаю hwnd на псевдоокно
 SocketThread := TIOServerThread.Create(FALSE, ClientSocket, PMWinHandle)
end;

procedure TSomeService.ServiceExecute(Sender: TService);
begin
   ...
   ServerSocket1.Port := ListenPort;
   ServerSocket1.ServerType := stThreadBlocking;
   ServerSocket1.ThreadCacheSize := 20;
   ServerSocket1.Active := True;
   while not Terminated do begin
     ServiceThread.ProcessRequests(True);
     sleep(0);
   end;
   ServerSocket1.Active := False;
end;

procedure TSomeService.FakeWndProc(var Msg: TMessage);
begin
 with Msg do begin
   case Msg of
     CM_CLIENT_IS_ACTIVE: begin
           ...
       end;
     CM_CLIENT_ADDCOMMAND: begin
           ...
       end;
     ...
   else
     Result := DefWindowProc(PMWinHandle, Msg, wParam, lParam);;
   end;
 end;
end;


Всё работает. По поводу невозможности потери сообщений. :)))
Читаем MSDN:

Therefore, if the recipient thread is in a modal loop (as used by MessageBox or DialogBox), the messages will be lost. To intercept thread messages while in a modal loop, use a thread-specific hook.

Ну и ещё ограничение очереди по кол-ву сообщений, влияние приливов-отливов и т.д.


 
Сергей М. ©   (2006-03-16 11:45) [16]


> Читаем MSDN


Опять же - код модально вылупившихся диалогов попросту игнорирует эти сообщения, поэтому они и теряются ... Но поступают-то они в очередь исправно !


> ограничение очереди по кол-ву сообщений


А нефих слать самому себе огромную себе кучу сообщений и не выбирать их при этом своевременно)


> sleep(0);


Хоть и не мешает оно, но вообще-то здесь оно лишнее - в ходе исполнения ProcessRequests(True) тред вызывает как минимум 1 ф-цию ожидания, переводящую его в kernel-time, и этого достаточно.


 
Lucefer   (2006-03-23 15:38) [17]

А как правильнее организовать цикл выборки сообщений в TTHread для передачи ему сообщения из потока сервиса (через PostThreadMessage)?


 
Сергей М. ©   (2006-03-23 15:55) [18]

Обычным образом:

TMyThread = class(TThread)
..
  procedure SomeServiceMessageHandler(var Msg: TMessage); message SM_SOMEMSGCODE;
..
end;

var
Msg: TMsg;
...
while not Terminated and GetMessage(Msg, 0, 0, 0) do
  Dispatch(Msg.Message);

//если есть опасность мемликов
//здесь можно выбрать оставшиеся в очереди (необработанные) сообщения SM_SOMEMSGCODE

while PeekMessage(Msg, ThreadId, SM_SOMEMSGCODE, SM_SOMEMSGCODE, PM_REMOVE) do...


 
Игорь Шевченко ©   (2006-03-23 15:56) [19]


> А как правильнее организовать цикл выборки сообщений в TTHread


А какие есть варианты ?


 
Lucefer   (2006-03-23 23:10) [20]

Наверное стоит новую тему начать.


 
Lucefer   (2006-03-23 23:58) [21]

http://delphimaster.net/view/4-1143146463/



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

Форум: "WinAPI";
Текущий архив: 2006.06.25;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.011 c
15-1148565801
dimodim-furyz
2006-05-25 18:03
2006.06.25
StaffCop.У когонить есть решение этой чумы?


2-1149451967
werb
2006-06-05 00:12
2006.06.25
диаграмма


2-1149420010
Vudu
2006-06-04 15:20
2006.06.25
Можно ли сделать тень под окном формы?


6-1139987331
Anton :-))
2006-02-15 10:08
2006.06.25
POP3 изменение subject входящего сообщения


2-1149622490
Mr tray
2006-06-06 23:34
2006.06.25
Что за символ #10?





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