Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Передача сообщения из порождённого TThread в родительский сервис [D7, Win2k, WinXP]


Страницы:   1 2

Lucefer ©   (2006-03-15 23:18:00) 

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


Lucefer   (2006-03-23 23:58:00) [1]

http://www.delphimaster.ru/cgi-bin/forum.pl?id=1143146463&n=5


Lucefer   (2006-03-23 23:10:00) [2]

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


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


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


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


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

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

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...


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

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


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


> Читаем MSDN


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


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


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


> sleep(0);


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


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

Сделал так:

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 10:13:00) [8]


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


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


tesseract   (2006-03-16 10:09:00) [9]

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


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


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


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

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


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


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


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

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


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


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


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

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


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


> 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;


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

function AllocateHWnd(Method: TWndMethod): HWND;

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

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

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


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

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


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

>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;


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

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


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

Спасибо за участие. Отвечаю по порядку.
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-15 23:33:00) [19]

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


Eraser   (2006-03-15 23:29:00) [20]


> Lucefer   (15.03.06 23:18)

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо