Форум: "Прочее";
Текущий архив: 2009.08.30;
Скачать: [xml.tar.bz2];
ВнизКласс очереди с событием Найти похожие ветки
← →
Индеец © (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;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.006 c