Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.08.30;
Скачать: CL | DM;

Вниз

Класс очереди с событием   Найти похожие ветки 

 
Индеец ©   (2009-06-26 12:25) [0]

Есть ли готовый класс аналог Tqueue но с событиями на добавление/удаление (на самом деле необходимо обрабатывать только добавление) элементов ? Разумеется, можно и переопределить Tqueue, добавив событие, но вдруг все уже есть ?


 
axis_of_evil ©   (2009-06-26 12:46) [1]

написать - быстрее, чем найти :>


 
Индеец ©   (2009-06-26 12:53) [2]

Может я и не правильное решение вижу. Мне необходимо: в обработке входящих tcp соединений, которые происходят в отдельных потоках (IdTCPServer) необходимы выполнять какие- то операции с объектом в VCL потоке. Я планирую создать очередь заданий, которая будет пополняться в критических секциях обработки входящих соединений и обрабатываться в VCL потоке. Может решение не правильное и есть более красивое ? Просто как в onexecute сервера выполнять некий код в синхронизации я не знаю.


 
Leonid Troyanovsky ©   (2009-06-26 13:00) [3]


> Индеец ©   (26.06.09 12:53) [2]

> обработке входящих tcp соединений, которые происходят в
> отдельных потоках (IdTCPServer) необходимы выполнять какие-
>  то операции с объектом в VCL потоке.

Ну, такая очередь уже есть: синхронных сообщений.
Сделаешь окну формы SendMessage, оно и выполнится
в VCL потоке.

--
Regards, LVT.


 
Индеец ©   (2009-06-26 13:14) [4]

Немного не понял, вам не сложно будет на примере показать?
Вот код:
unit Unit84;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, IdContext, StdCtrls, IdBaseComponent, IdComponent, IdCustomTCPServer,
 IdTCPServer,ExtCtrls, IdScheduler, IdSchedulerOfThread,
 IdSchedulerOfThreadDefault, IdAntiFreezeBase, IdAntiFreeze,JclQueues;

type
 TForm84 = class(TForm)
   tcps1: TIdTCPServer;
   Button1: TButton;
   idntfrz1: TIdAntiFreeze;
   procedure Button1Click(Sender: TObject);
   procedure tcps1Execute(AContext: TIdContext);
 private
   procedure ontt(sender:TObject);
   procedure resettt;
 public
   { Public declarations }
 end;

var
 Form84: TForm84;
 tt:Ttimer;
implementation

{$R *.dfm}

procedure TForm84.Button1Click(Sender: TObject);
begin
tt:=ttimer.Create(nil);
tt.Interval:=5000;
tt.OnTimer:=ontt;
tt.Enabled:=true;
end;

procedure TForm84.ontt(sender: TObject);
begin
Form84.caption:=DateTimeToStr(now);
end;

procedure TForm84.resettt;
begin
tt.Enabled:=false;
tt.Free;
tt:=ttimer.Create(nil);
tt.Interval:=10000;
tt.OnTimer:=ontt;
tt.Enabled:=True;
end;

procedure TForm84.tcps1Execute(AContext: TIdContext);
begin
resettt;
acontext.Connection.Disconnect;
end;

end.

Как правильно реализовать так, чтобы после Onexecute таймер корректно переинициализировался ?


 
axis_of_evil ©   (2009-06-26 13:22) [5]


t.Enabled:=false;
tt.Free;
tt:=ttimer.Create(nil);
tt.Interval:=10000;
tt.OnTimer:=ontt;


Enabled := False;
Interval := 10000;

зачем уничтожать объект и заново создавать?
// не вижу связи описанного в [4] с описанным в [0] %>


 
Индеец ©   (2009-06-26 13:26) [6]


> зачем уничтожать объект и заново создавать?

Сделано для наглядности. Можно написать по другому:
unit Unit84;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, IdContext, StdCtrls, IdBaseComponent, IdComponent, IdCustomTCPServer,
 IdTCPServer,ExtCtrls;

type
 TForm84 = class(TForm)
   tcps1: TIdTCPServer;
   Button1: TButton;
   idntfrz1: TIdAntiFreeze;
   procedure Button1Click(Sender: TObject);
   procedure tcps1Execute(AContext: TIdContext);
 private
   procedure ontt(sender:TObject);
   procedure resettt;
 public
   { Public declarations }
 end;

var
 Form84: TForm84;
 tt:Ttimer;
implementation

{$R *.dfm}

procedure TForm84.Button1Click(Sender: TObject);
begin
tt:=ttimer.Create(nil);
tt.Interval:=5000;
tt.OnTimer:=ontt;
tt.Enabled:=true;
end;

procedure TForm84.ontt(sender: TObject);
begin
Form84.caption:=DateTimeToStr(now);
end;

procedure TForm84.resettt;
var tt1:TTimer;
begin
tt.Enabled:=false;
tt1:=Ttimer.Create(nil);
tt1.Interval:=10000;
tt1.OnTimer:=ontt;
tt1.Enabled:=True;
end;

procedure TForm84.tcps1Execute(AContext: TIdContext);
begin
resettt;
acontext.Connection.Disconnect;
end;

end.

Как правильно себя повести в этом случае чтобы таймер tt1 работал корректно ?


 
Leonid Troyanovsky ©   (2009-06-26 14:20) [7]


> Индеец ©   (26.06.09 13:26) [6]

> Как правильно себя повести в этом случае чтобы таймер tt1
> работал корректно ?

В этом случае много неправильного.
1. var tt: TTimer  - глобальная переменная - MD.
2. var tt1: TTimer - локальная переменная здесь тоже не нужна,
каждый вызов resettt плодит новый таймер.

Да и зачем этот мазохизм, когда достаточно бросить 1 таймер на форму.

Для того, чтобы перезапустить этот таймер из другого потока
можно описать у формы метод:

procedure WMUser(var msg: TMessage); // message WM_USER;
begin
 Timer1.Enabled := False;
 Timer1.Interval := 10000;
 Timer1.Enabled := True;
end;

и вызывать его из функции потока путем SendMessage.

--
Regards, LVT.


 
Индеец ©   (2009-06-26 14:34) [8]

Понял, спасибо за разъяснения. Но возник еще один вопрос: а если нам надо сообщить это некое событие объекту, не имеющему handle ? только тогда на форме или в самом приложении писать некий диспечер, который будет получать сообщения и перенправлять их в зависимости от параметров тому или иному объекту ?


 
Leonid Troyanovsky ©   (2009-06-26 14:44) [9]


> Индеец ©   (26.06.09 14:34) [8]

>  а если нам надо сообщить это некое событие объекту,

Ты мог заметить, что шлем сообщение не TTimer, хотя
у него тоже есть окно.

Ну, а насчет параметров - у SendMessage их целых два.

--
Regards, LVT.


 
Ega23 ©   (2009-06-26 14:48) [10]


> а если нам надо сообщить это некое событие объекту, не имеющему
> handle ? только тогда на форме или в самом приложении писать
> некий диспечер, который будет получать сообщения и перенправлять
> их в зависимости от параметров тому или иному объекту ?


Я бы так сделал. Есть поток. Есть очередь. Есть критсекция. Основной поток время от времени (да хоть по таймеру, или в OnIdle) спрашивает Count в очереди. Если больше нуля - начинает вычитывать очередь (заблокировав её через крит.секцию)
Дополнительный поток уже сам кладёт в эту очередь сообщения, также заблокировав очередь через крит.секцию.


 
Индеец ©   (2009-06-26 15:04) [11]


> Я бы так сделал. Есть поток. Есть очередь. Есть критсекция.
>  Основной поток время от времени (да хоть по таймеру, или
> в OnIdle) спрашивает Count в очереди. Если больше нуля -
>  начинает вычитывать очередь (заблокировав её через крит.
> секцию)Дополнительный поток уже сам кладёт в эту очередь
> сообщения, также заблокировав очередь через крит.секцию.
>

Я как раз примерно так и планировал (отсюда и название темы). Сейчас все- таки больше склоняюсь именно к организации очереди.

> Ты мог заметить, что шлем сообщение не TTimer, хотя
> у него тоже есть окно.
>
> Ну, а насчет параметров - у SendMessage их целых два.

Про ttimr сразу не подумал, большое спасибо


 
Индеец ©   (2009-06-26 15:06) [12]

А, кстати, обратный обмен каким образом лучше сделать?
Т.е. сторонний поток каким- то образом сообщил главному потоку о необходимом действии, главный поток его (действие) совершил, и надо сообщить стороннему потоку результат этот действия.


 
Сергей М. ©   (2009-06-26 15:11) [13]


> Индеец ©   (26.06.09 15:06) [12]


У любого кодового потока априори имеется своя индивидуальная очередь сообщений (она автоматически создается системой для потока, вызвавшего как минимум один раз Get/PeekMessage).
Во многих случаях этой очереди вполне достаточно для организации межпоточной синхронизации.


 
Индеец ©   (2009-06-26 15:24) [14]


> У любого кодового потока априори имеется своя индивидуальная
> очередь сообщений (она автоматически создается системой
> для потока, вызвавшего как минимум один раз Get/PeekMessage).
> Во многих случаях этой очереди вполне достаточно для организации
> межпоточной синхронизации.

А по какому принципу происходит тогда обмен сообщениями ? между какими хенделами ? Просто в onexecute idtcpserver в acontext так и не нашел способа получить доступ непосредственно к потоку


 
Сергей М. ©   (2009-06-26 15:34) [15]


> по какому принципу происходит тогда обмен сообщениями ?


Поток-отправитель сообщения вызывает ф-цию PostThreadMessage, передавая 1-м параметром ThreadID потока-получателя.
Если поток-получатель существует и у него существует очередь сообщений, ф-ция ставит сообщение в хвост очереди сообщений потока-получателя и немедленно возвращает управление.

Поток-получатель по мере заинтересовааности в получении сообщений обращается к своей очереди вызовами Get/PeekMessage.


 
Индеец ©   (2009-06-26 15:45) [16]

Принцип понял, но совсем не понятно как этим воспользоваться в Indy в acontext


 
Сергей М. ©   (2009-06-26 16:24) [17]


> Индеец ©   (26.06.09 15:45) [16]


Если ты не устанавливал явно у объекта IdTCPServer св-во Sheduler, то параметр AContext: TIdContext в обраб-ках событий, в которых он фигурирует, есть ничто иное как TThread.

Т.е. простое приведение типа TThread(AContext) даст доступ по всем публичным и опубликорванным св-вам объекта-потока, "скрывающегося" за страшным словом "контекст")


 
Индеец ©   (2009-06-26 17:49) [18]

Спасибо, зато теперь встало на место понятие и назначение шелдеров =)


 
Индеец ©   (2009-06-26 21:29) [19]

Кстати, а не проще будет тогда код, использующий конкурирующие ресурсы главного потока просто выполнять в TIdThread(AContext).Synchronize(); ?


 
Сергей М. ©   (2009-06-27 15:08) [20]


> Индеец ©   (26.06.09 21:29) [19]


Во-первых, это protected-метод.
Для доступа к нему потребуется организовывать своего наследника TIdThread, что повлечет за собой необходимость явного задействования планировщика
Оно тебе надо ?

Во-вторых, доп.поток, обслуживающий своего клиента, вызвав Synchronize будет вынужден ждать, пока осн.поток освободится для обработки указанного метода. Это м.б. неприемлемо с т.з. оперативности обслуживания клиента.


 
Индеец ©   (2009-06-29 09:23) [21]

Более детально покопавшись в Indy решил проблему так:
так как мне все- таки по логике программы необходимо ждать окончания выпонения метода основного потока внутри подключения, то синхронизацию использовать логичнее, сделал так:
uses ... idsync;
TIdSync.SynchronizeMethod



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

Текущий архив: 2009.08.30;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.016 c
4-1216039147
Gec
2008-07-14 16:39
2009.08.30
Получить Canvas фомы


2-1246017930
VoyagerEternal
2009-06-26 16:05
2009.08.30
Как продолжить выполнение программы после искл. ситуации(raise)?


4-1215758422
Thunderstorm
2008-07-11 10:40
2009.08.30
OpenSSL


2-1246549168
vslabchenko
2009-07-02 19:39
2009.08.30
Парадокс с ShellExecute


2-1246216548
Pasha
2009-06-28 23:15
2009.08.30
Обращение к ячейкам в БД