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

Вниз

Тонкости обработки потоков в моделях tmFree и tmApartment   Найти похожие ветки 

 
Erik ©   (2004-03-12 11:08) [0]

Я создаю COM объект, который использует глобальный класс. В классе разумеется есть синхронизация(TMultiReadExclusiveWriteSynchronizer). Создается exe сервер.(..., ciMultiInstance, tmApartment)
Я хочу уточнить почему при использовании модели tmApartment при котором клиент COM объект находиттся с самом exe, все зависает при подключении второго клиента. Клиенты имулируются для теста вот так:
 for i := 0 to 10 do
 begin
   Test[i] := CoProtocol.Create as IProtocolDisp;
   ChkCaptureClick(ChkCapture);
   UserID := Random(1000);
   Test[i].Login(EdName.Text, EdPassword.Text, UserID);
Причем у меня имеется нотификация но добавление клиентов, но отрабатывает только для перврго клиента. Причем висит все на ntdll.RtlGetDaclSecurityDescriptor: - это видно если на Pause нажать и в ASM войти. Это, чтож получается, что я в ожидании вишу?! Я конецно знаю, что tmApartment сам обеспечивает синхронизацию, не немогу понять почему зависает в моем случае?
 Причем в модели Free все работает прекрастно.
"Понимание потоковых моделей в COM при программировании на Delphi" Бин Ли - читал, но может кто из профи разяснит мой случай? А то неизветсно сколько прочитать придется пока разберусь.


 
Asdor ©   (2004-03-12 11:45) [1]

Надо больше кода...
Я щас попробовал простейший объект с одним методом и цикл как у тебя - все нормально работает (так как все работает последовательно).
В чем могут быть проблемы:
1. при апартментовой модели в ехе сервере все фабрики классов работают в главном STA.
2. если фабрика класса не создает для твоих ком-объектов отдельные потоки, то все твои объекты также находятся в главном STA. Соответственно - никакой параллельной работы.


 
Erik ©   (2004-03-12 12:53) [2]

Наверное действительно несоздает. Сейчас я тестирую комбинируя с клиентом из другой апликации, там точно создает. А какой код привести? Вот начало:
function TProtocol.Login(const User, Password: WideString; var ID: Integer): RetStatus;
begin
Database.Connected := False;
Database.LogonUsername  := User;
Database.LogonPassword := Password;
Database.Connected := True;

fUserName := User;
 if ID < 1 then
 ID := fUserID
 else fUserID := ID;
fLoggedIn := True;
 Block.AddUser(fUserID, User);
Result := rtOk;
end;
В Block.AddUser стоит FLock.BeginWrite;


 
Гаврила   (2004-03-12 12:54) [3]

а случайно не TAutoObjectFactory используется в качестве фабрики классов?
если да, то там многопоточность не реализована, в отличие от TComponentFactory


 
Asdor ©   (2004-03-12 13:31) [4]

2 Гаврила
 Да, не реализована и все ком-объекты и фабрики классов лежат в main STA.

2 Eric
а FLock.EndWrite?


 
Erik ©   (2004-03-12 14:49) [5]

FLock.EndWrite разумеется есть, даже в try finally взято. Используется TComponentFactory и ComServer.UIInteractive := False;
Еще я делаю марщалинг, для хранения списка всех com сессий.


 
Asdor ©   (2004-03-12 15:02) [6]

А сервер под отладкой если запустить, то где виснет (в твоем коде а не ntdll.RtlGetDaclSecurityDescriptor)?

Я думаю надо код смотреть полностью...


 
Erik ©   (2004-03-12 15:36) [7]

Выяснил в где виснет. Оказалось на FLock.BeginRead; или FLock.BeginWrite; Хотя они всегда в паре стоят. Например здесь
При вызове DelReserv виснет, хотя при модели Free и вызове из нетри exe невиснет.
procedure TInfoList.DelReserv(const UserID, ReservId: Cardinal);
Var
   i: Integer;
   CurHole: PHole;
   CurUser: PCounter;
Label ExitProc;
begin
 FLock.BeginRead;
 try
   if FindID(UserID, CurUser) = RetError then
     goto ExitProc;

   CurHole := FRes.FindID(ReservId);
   if not Assigned(CurHole) then
     goto ExitProc;

   DecReserv(CurUser, CurHole);

ExitProc:
 finally
   FLock.EndRead;
 end;
end;

procedure TInfoList.DecReserv(User: PCounter; Hole: PHole);
Var
   i: Integer;
begin
 FLock.BeginWrite;
 try
   for i := 0 to User.Size-1 do
     if (User.Hole[i] = Hole)  then
     begin
       if (User.Size-1-i > 0) then
         Move(User.Hole[i+1], User.Hole[i], SizeOf(User.Hole));
       Dec(User.Size);
       ReallocMem(User.Hole, User.Size * SizeOf(Pointer));
       Break;
     end;
   if Assigned(User.Last) then
   begin
     Dispose(User.Last);
     User.Last := nil;
   end;
   Hole.Stat := idUndo;
   User.Last := Hole;
   FRes.Delete(Hole, False);

   if Assigned(fNotify) then
     fNotify(User.UserID, User.Last, lnDecReserv);
 finally
   FLock.EndWrite;
 end;
end;


 
Erik ©   (2004-03-12 15:44) [8]

Наверное зря я воспользовался TMultiReadExclusiveWriteSynchronizer, он ведь все по физическим потокам различает. А какие там в STA или MTA потоки образуются, никто незнает. Наверное поэтому и зависает, попробую критические секции поставить. Может я неправ кто в курсе?


 
Asdor ©   (2004-03-12 15:52) [9]

FNotify это что? интерфейс обратного вызова?
Как он реализован и как используется?
Нормально ли выходит первый клиент из DecReserv?

Раз блокировка на BeginRead, значит кто-то не вышел из BeginWrite...

В общем, взаимоблокировки с callback в апарментовой модели это непросто. там всякие MessageFilter"ы используются... и т.п.


 
Asdor ©   (2004-03-12 15:53) [10]

Критические секции тебя не спасут и все будет работать так же...


 
Erik ©   (2004-03-12 16:34) [11]

Ты так думаеш? :( Могу сказать что первый клиет отрабатывет нормально. Могу сказать, что без нотификации все работает нормально, только для одного клиента.
Да FNotify интерфейс обратного вызова. Завазан на главную форму приложения. Там так:
procedure TAppControl.Notify(UserID: Integer; Ptr: Pointer; Action: TCounterNotification);
begin
 if not Application.Terminated then
 begin
   case TCounterNotification(Action) of
     lnAdded, lnDeleted:
       Move(PCounter(Ptr)^, BufUser, SizeOf(BufUser));
     lnDecReserv, lnAddReserv:
       begin
         Move(PHole(Ptr).Params, BufInfo.Detail, SizeOf(BufInfo.Detail)-SizeOf(BufInfo.Detail.TeenID));
         BufInfo.Detail.TeenID := Copy(PHole(Ptr).Params.TeenID);
       end;
   end;
   SendMessage(Handle, wmNotify, UserID, Ord(Action)); //Integer(Ptr)
 end;
end;


 
Asdor ©   (2004-03-12 16:55) [12]

TAppControl.Notify не вернет управления пока главная форма не обработает сообщение. Таким образом, на сервере мы ждем, пока клиент полностью не обработает сообщение (все синхронно).
Если у тебя цикл из самого первого сообщения реализован в методе главной формы как реация на какой-нить Button1.Click, то вот он твой deadlock...
Если в SendMessage ты не передаешь никаких указателей (а ты вроде не передаешь), то замени SendMessage на PostMessage, тогда главная форма обработает твое сообщение когда у нее будет возможность это сделать...


> без нотификации все работает нормально, только для одного
> клиента.

Этого не понял. т.е. если нотификации нет - то тоже все висит при нескольких клиентах?
Если это так, То вышенаписанное мною видимо неверно.

Это пока все, что я могу понять из приведенного кода.


 
Erik ©   (2004-03-15 10:04) [13]

Могу сказать, что поробовал снести все FLock в пограмме и заустить ее как  tmApartment. Все работает. Попробую с PostMessge, но я недумаю что это существенно, поскольку пробовал и без нотификации.
 Может ктонибудь знает как в режиме Free использовать синхронизацию?


 
Asdor ©   (2004-03-15 10:41) [14]

А что именно тебя интересует?


 
Erik ©   (2004-03-15 12:40) [15]

Тоесть можно ли вобще ставить подряд 2 комманды.
FLock.BeginRead;
FLock.BeginWrite;



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

Форум: "Основная";
Текущий архив: 2004.04.04;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.49 MB
Время: 0.032 c
1-1079637510
maxXP
2004-03-18 22:18
2004.04.04
Как определить запущена ли программа...


7-1074238356
Serge
2004-01-16 10:32
2004.04.04
Disable Start menu on descktop doubleclik


4-1074877133
Miau
2004-01-23 19:58
2004.04.04
Как узнать, что форму перемещают ?


4-1074539580
Arr'acctur
2004-01-19 22:13
2004.04.04
StdOut


7-1075073038
Slash_from_Ryazan
2004-01-26 02:23
2004.04.04
Как узнать Имя пользователя в Виндовс





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