Форум: "Основная";
Текущий архив: 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