Форум: "Основная";
Текущий архив: 2006.01.01;
Скачать: [xml.tar.bz2];
Внизкак отработать события СОМ объекта принадлежащего классу TThread Найти похожие ветки
← →
Rule © (2005-12-02 15:07) [0]описываю ситуацию, в приложении создается отдельный поток, в этом потоке создается СОМ-сервер, который обладает событиями, для простоты эксперемента возьмем одно событие. Так вот когда происходит событие в сервере (сервер написаный мной) сервер выполняет вот такой вот код ...
try
L := ClientList.LockList;
for i:=L.Count-1 to L.Count-1 do
begin
T := TTerminal(L[i]);
T.FLastCardNumber:=FLastCardNumber;
T.FEmitent := FEmitent;
T.FClientInfo := FClientInfo;
T.FcardStart := FcardStart;
T.FCardEnd := FCardEnd;
T.FLimits := FLimits;
T.FLimitCount := FLimitCount;
T.FPurseCount := FPurseCount;
T.FPurse := FPurse;
if Assigned(T.Events) then T.Events.OnCardInsert;
end;
finally
ClientList.UnlockList;
end;
в списке клиентов хранятся ссылки на интерфейс клиентов ...
так вот смысл в чем, что когда происходит событие то до ходит до строки
if Assigned(T.Events) then T.Events.OnCardInsert;
и пытается выполнить метод клиента и сервер подвисает, в это время на клиенте поток крутится в методе Execute в цикле, пока его не завершит по флагу VCL поток. И вот когда поток выходит из цикла Execute вот тогда и срабатывает событие ... тоесть событие сервера отработается только когда выйдет из Execute.
Вопрос в том как это побороть ??? тоесть мож в цикле Execute можно узнать произошло ли событие или нет ? можно конечно сделать флаг объекта что при возникновении события он устанавливается ну а в цикле Execute проверять этот флаг, но это не выход, потомучто хотелось бы оставить всетаки нормальные события.
для полноты картины привожу полный код потока ...
unit uShlumbThread;
interface
procedure TShlumbThread.Execute;
var
List:TList;
QE:PShlumbQueryElement;
begin
inherited;
CoInitializeEx(nil,COINIT_APARTMENTTHREADED);
StartTerminal;
//FShlumb.StartPingCard;
while not FTerminate do
begin
try
List:=shlumbQueryList.LockList;
if List.Count>0 then
QE := List.First
else
QE := nil;
finally
shlumbQueryList.UnlockList;
end;
// FShlumb.StartPingCard;
if QE<>nil then
begin
if QE.name="debetadv" then
begin
PayMoney(QE.summa);
end;
if QE.name="endping" then
begin
FShlumb.EndPingCard;
end;
if QE.name="startping" then
begin
FShlumb.StartPingCard;
end;
//отчищаем элемент
try
List:=ShlumbQueryList.LockList;
List.Delete(List.IndexOf(QE));
Dispose(QE);
//P:=nil;
finally
ShlumbQueryList.UnlockList;
end;
end;
end;
if FShlumb.IsCardPinging then FShlumb.EndPingCard;
FShlumb.Free;
CoUninitialize;
end;
procedure TShlumbThread.StartTerminal;
var
IFI:TIniFile;
i:integer;
ncomport:OleVariant;
res:WaitResult;
begin
FShlumb := TTerminal.Create(nil);
FShlumb.AutoConnect:=True;
FShlumb.OnCardInsert := Main.ShlumbCardInsertMain;
FShlumb.OnCardRemove := Main.ShlumbCardRemoveMain;
FTerminate := false;
FLastPingCard := "";
IFI := TIniFile.Create(ExtractFilePath(Application.ExeName)+"settings.ini");
i := IFI.ReadInteger("SHLUMB","COMPORT",5);
case i of
1: ncomport := puCOM1;
2: ncomport := puCOM2;
3: ncomport := puCOM3;
4: ncomport := puCOM4;
5: ncomport := puCOM5;
6: ncomport := puCOM6;
7: ncomport := puCOM7;
8: ncomport := puCOM8;
9: ncomport := puCOM9;
else ncomport := puCOM5;
end;
IFI.Free;
FShlumb.InitUnit(bru9600,dbuSeven,pruEven,ncomport,sbuOneStopBit,res);
if res<>WR_Ok then raise Exception.Create("Ошибка при открытии порта терминала Р+, дальнейшая работа программы невозможна !!!");
end;
помогите пожалйста, всем благодарен, кто обратил внимание ... надеюсь информация достаточная и полная ...
← →
Rule © (2005-12-02 15:08) [1]поправка это не полный код потока, а метод экзекьют и метод создания комобъекта, который вызывается вначале экзекьют
← →
Rule © (2005-12-02 15:16) [2]ещё одна поправка процедуры генерации сообщения на сервере:
try
L := ClientList.LockList;
for i:=0 to L.Count-1 do
begin
T := TTerminal(L[i]);
T.FLastCardNumber:=FLastCardNumber;
T.FEmitent := FEmitent;
T.FClientInfo := FClientInfo;
T.FcardStart := FcardStart;
T.FCardEnd := FCardEnd;
T.FLimits := FLimits;
T.FLimitCount := FLimitCount;
T.FPurseCount := FPurseCount;
T.FPurse := FPurse;
if Assigned(T.Events) then T.Events.OnCardInsert;
end;
finally
ClientList.UnlockList;
end;
← →
Digitman © (2005-12-02 16:06) [3]что говорят результаты пошаговой трассировки сабжа во встроенном отладчике ?
← →
Rule © (2005-12-02 16:08) [4]Digitman © (02.12.05 16:06) [3]
висит на сервере if Assigned(T.Events) then T.Events.OnCardInsert;
до тех пор пока не закончится эезекьют на клиенте, как только н заканчивается, так сразу выполняется бработчик на клиенте ...
← →
Rule © (2005-12-02 16:09) [5]вот єтот обработчик на сервере вызывать через синхронайз метод ... ща буду пробовать
← →
Набережных С. © (2005-12-02 17:14) [6]
> Rule ©
Сообщения кто из очереди выбирать будет, Пушкин? Дык он уже умер, как я недавно узнал:(
← →
Rule © (2005-12-02 17:34) [7]Набережных С. © (02.12.05 17:14) [6]
вот как раз это меня и интересует, как мне выбрать сообщения из очереди ???
← →
Набережных С. © (2005-12-02 18:02) [8]
> Rule © (02.12.05 17:34) [7]
> в это время на клиенте поток крутится в методе Execute
> в цикле, пока его не завершит по флагу VCL поток. И вот
> когда поток выходит из цикла Execute вот тогда и срабатывает
> событие ...
В общем, довольно смутное описание, но, судя по всему, в этом самом цикле, в котором "крутится клиент", и надо бы выбирать и диспетчиризовать сообщения из очереди ентого клиентского потока. Тут, вишь ли, дело такое, СОМ для синхронизации меж потоками в STA использует сообщения, а выбрать их некому, получаецца. Вот если внутри клиентского вызова метода, то там дело другое, там за это COM отвечает, а вот снаружи ето дело клиента, ага.
А вообще-то, я тут второй литр балтики дососал, так что ты c моими советами поосторожней:)) Давай завтра что-ли, если не решишь. А пока бы поподробней расписал. Вот представь человека, который твоего кода в глаза не видел, где клиент, где сервер, какой сервер, какой код к кому - фиг знает... Вот для такого человека и расскажи:)
← →
Rule © (2005-12-02 18:25) [9]Набережных С. © (02.12.05 18:02) [8]
огромное спасибо, значит проблемму решил таким образом, в принципе то её обойти можно было, но это уже не та история, все решния пришли сразу :-)))
так вот решение такое, так как у меня МТА, когда я писал сервер я не знал зачем оно, только код усложняется, но решил поупрожнятся, но щас пригодилось :-) так вот просто в VCL потоке прописал CoInitFlags:= COINIT_MULTITHREADED;
перед инициализацией приложения, таким образом у меня стал возможен доступ к СОМ серверам созданым в других потоках и обработчики событий я прицепил в методе Create моего потока.
Таким образом оплучилось что экзекьют себе пусть крутиться хоть до опупения, а вот обработчики будут выполняться в основном потоке, который с радостью отвечает всегда серверу :-)))
спасибо всем, если кто нарвется на похожую тему, то могу дать ссылку которая подтолкнула на эту мысль, в принципе для меня небыло ничего особо информативного но хорошо систематизированая информация помогла собрать мысли в кучу.
ссылка:
http://emanual.ru/download/210.html
← →
Rule © (2005-12-02 18:28) [10]оффтоп:
ЗЫ: всетаки тяжело с бодуна проги писать :-))) особенно многопоточные :-))), присоеденяюсь к Сергею и иду пить пива :-))).
большое спаибо всем кто откликнулся :-)))
сорри за оффтоп
← →
Набережных С. © (2005-12-02 19:54) [11]
> Rule ©
Ну и замечательно:) Особо одобряю на счет пива:))) Тока не забывай, что в MTA нельзя строить предположений, в каком потоке СОМ будет выполнять тот или другой вызов, какой сочтет подходящим, тот и выберет. Значить, и синхронизацию надобно надежную обеспечить, не закладываться на основной.
← →
Rule © (2005-12-02 20:18) [12]Набережных С. © (02.12.05 19:54) [11]
спасибо за совет так и сделал, с двойной защитой, главное чтоб перекрестных блокировок теперь не возникло, завтра буду сервер на сей предмет изучать и проверять, спасибо большое за советы
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2006.01.01;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.011 c