Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Виснет программа! CriticalSection или ?


Страницы:   1 2

Miralex ©   (2005-01-18 11:54:00) 

Мастера помогите разобраться почему моя программа зависает.
Использую я свой класс в программе. В классе я перекрываю критическими секциями все места, где возможно выполение из потока! В итоге почемуто моя программа виснет. Помогите разобраться.

Кусочек кода, на который я грешу:

procedure TCharacter.GameSendSHex(SHex : String; Encrypt : boolean);
var I, Len: Integer;
   BufIn, BufOut : PArray;
begin
SocketSection.Enter;
if not GameClient.Active then
       begin
       SocketSection.Leave;
       Exit;
       end;
New(BufIn);
New(BufOut);
Len := Length(SHex);
{Конвертируем SHex в Array of byte}
if (Len = 0) or (Len mod 2 <> 0) then
begin
AddtoDebugMemo('Error converting SHex to Array of byte');
SocketSection.Leave;
Exit;
end;
for I := 0 to ((Len div 2)-1) do BufIn^[I] := StrToInt('$'+Copy(SHex, I*2+1, 2));
Len := Len div 2;
{Криптуем методом BlowFishCrypt если Encrypt=true и EncryptMetod=2}
if Encrypt and (EncryptMetod = 2) then BlowfishEncrypt(BlowfishCryptObj,BufIn,BufOut,Len)
else for i := Low(BufOut^) to High(BufOut^) do BufOut^[i]:=BufIn^[i];
{Пытаемся отослать байтики серверу}
if GameClient.Socket.Connected then
begin
try
GameClient.Socket.SendBuf(BufOut^,Len);
AddtoDebugMemo('Client send '+inttostr(Len)+' bytes: '+SHex);
except
AddtoDebugMemo('Error in Socket.SendBuf');
end;
end
else AddtoDebugMemo('You try send some bytes, but Character is not Connected');
SocketSection.Leave;
Dispose(BufIn);
Dispose(BufOut);
end; {End TCharacter.GameSendSHex}

procedure TCharacter.SendUnicodeText(Value : String);
var i : Integer;
   S,SHex : String;
begin
S := Value;
{Если в S пусто то выходим}
if Length(S)=0 then Exit;
{в S - то что мы хотим сказать серверу}
SHex := '';
{Дописываем в конец 2 нуля}
SHex := '0000';
{Вставляем текст в формате '00' буква '00' буква и тд}
for i:=Length(s) downto 1 do SHex := '00' + IntToHex(ord(S[i]),2) + SHex;
{Добавляем в начало язык (4 байта)}
{Покачто только русский RUS='52 55 53'}
SHex := '52555300'+SHex;
{Добавляем тип(1 байт), цвет(2 байта) и шрифт(2 байта)}
SHex := '0002B20003'+SHex;
{Длина пакета}
SHex := IntToHex((Length(SHex) div 2)+3,4) + SHex;
SHex := 'AD' + SHex;
GameSendSHex(SHex,true);
end;


Из потока я вызываю так:
TCharacter(Char).SendUnicodeText(S);

Критических секций в потоке нету, так как они внутри класса перекрывают все! Насколько я понял так можно их использовать. Или нет?

В итоге программа зависает на N-ом использовании TCharacter(Char).SendUnicodeText(S) из потока.

Думал что гдето зацикливаються критические секции - поубирал все что неиспользую в данный момент. Всеравно виснет.

Мастера, подскажите пожалуйста где ошибка?


Miralex   (2005-01-18 15:30:00) [1]

понял. Большое спасибо.


Digitman   (2005-01-18 15:13:00) [2]


> значит как я понял CriticalSection я могу использовать если
> надо защитить переменную


не совсем так.

крит.секцией ты можешь защишать все что подконтрольно тебе как разработчику кода.

в случае же с VCL ее внутренний код ничего не знает ни о каких твоих кр.секциях, поэтому чуть ли не единственный способ защититься от отказов, связанных с мультипоточным доступом к объектам VCL - осуществлять этот доступ в одном и том же (основном) трэде, что как раз и реализует синхронизация с использованием метода TThread.Synchronize


Miralex   (2005-01-18 14:55:00) [3]

значит как я понял CriticalSection я могу использовать если надо защитить переменную!.. а если я хочу еще и VCL и тд - то только Sincronize?


Digitman   (2005-01-18 14:50:00) [4]


> Miralex ©   (18.01.05 14:42) [18]


да, синхронизация и здесь будет также необходима.


Miralex   (2005-01-18 14:42:00) [5]


> > и например в потоке я просто напишу:
> > TCharacter(Char).CharName:='Name1';
> >
> > ошибок не будет?
>
>
> не будет.


Здесь в событии EventOnCharNameChanged() у меня также пишеться новое значение на форме! и что делать? тоже Sincronize?


Digitman   (2005-01-18 14:39:00) [6]


> и например в потоке я просто напишу:
> TCharacter(Char).CharName:='Name1';
>
> ошибок не будет?


не будет.
ты же защитил поле fCharName кр.секцией !
только один трэд в каждый момент времени будет иметь к нему доступ


> Береться значение и добавляеться в конец TMemo, который
> на форме!
> Необходимо использовать в потоке через Sincronize?


да, синхронизация обязательна.
класс TMemo - в составе VCL, а все виз.объекты VCL в подавляющем большинстве прогр.случаев требуют синхронизацию обращений к ним с осн.трэдом


Miralex   (2005-01-18 14:34:00) [7]


> что здесь, в теле этого метода, творится ? ввызываются методы/св-ва
> некоего Memo ?


Береться значение и добавляеться в конец TMemo, который на форме!
Необходимо использовать в потоке через Sincronize?


Miralex   (2005-01-18 14:32:00) [8]

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

property CharName : String read GetCharName write SetCharName;

.....................................

{----------------------CharName---------------------}
function TCharacter.GetCharName:String;
begin
CharNameSection.Enter;
Result := fCharName;
CharNameSection.Leave;
end;
procedure TCharacter.SetCharName(Value:String);
begin
CharNameSection.Enter;
fCharName := Value;
//Send Event
if Assigned(EventOnCharNameChanged) then EventOnCharNameChanged(Self,Value);
CharNameSection.Leave;
end;


и например в потоке я просто напишу:
TCharacter(Char).CharName:='Name1';

ошибок не будет?


Digitman   (2005-01-18 14:27:00) [9]


> AddtoDebugMemo


что здесь, в теле этого метода, творится ? ввызываются методы/св-ва некоего Memo ?

делать это в доп.трэде недопустимо.


Digitman   (2005-01-18 14:22:00) [10]


> Miralex ©   (18.01.05 14:16) [12]


навскидку - да, правильно.
только GameStarted - это не переменная, это св-во класса
а fGameStarted - это член (поле) класса


Miralex   (2005-01-18 14:16:00) [11]

Полно переменных которые мне необходимо будет использовать и потоке. Ну например:
property GameStarted : boolean read fGameStarted;
она мне нужна и в потоке.. причем в основной программе я буду и записывать в нее и читать из нее! в Потоке же мне необходимо будет только читать значение из нее.

я думал использовать критическую секцию.

в программе переписать на
property GameStarted : boolean read GetGameStarted;

ф-цию GetGameStarted описать так:
begin
GameStartedSection.Enter;
Result := fGameStarted;
GameStartedSection.Leave;
end;

в классе поменять везде где чтение на GetGameStarted и где запись поменять на SetGameStarted(Value : Boolean).

при этом процедуру SetGameStarted сделать с критической секцией по аналогии GetGameStarted!

Так правильно?


Digitman   (2005-01-18 13:39:00) [12]


> можно по подробнее для режима NonBlocking


этот вопрос д.б. задан отдельно в разделе "Сети"


> Мне надо защищать как и переменные


какие переменные конкретно ? покажи пальцем на примере упомянутого тобой кода ..


Miralex   (2005-01-18 13:18:00) [13]


> Digitman

а можно по подробнее для режима NonBlocking...

и еще вопрос:
Что в данном случае лучше и для чего использовать.. Мне надо защищать как и переменные так и сокет соединение.


Digitman   (2005-01-18 13:11:00) [14]


> Miralex ©   (18.01.05 12:49) [6]


крит.секцию можно использовать где угодно


> И так сделать для всех процедур, которые я использую из
> потока?


крит.секциями защищаются не процедуры, а программные ресурсы

у тебя, очевидно, есть как минимум один программный ресурс, который следует защищать - это объект класса TClientSocket.. он у тебя выполняет ф-ции единого трансп.канала для всех твоих трэдов, и одновременное обращение к этому объекту со стороны более чем одного трэда недопустимо

т.е. в ДАННОМ контексте в блок аправления крит.секцией достаточно включить лишь обращение к объекту GameClient, и то при условии что он работает в режиме ctBlocking .. при ctNonBlocking же код ощутимо усложняется, такая простейшая защита в этом случае никуда не годится из-за асинхронности работы гнезда


Miralex   (2005-01-18 12:56:00) [15]

Я так и не могу понять как мне надо делать?

Понаходить в коде все обращения GameSendSHex(SHex,true) и поменять на
SocketSection.Enter;
try
GameSendSHex(SHex,true);
finally
SocketSection.Leave;
end;

И так сделать для всех процедур, которые я использую из потока?


TUser   (2005-01-18 12:52:00) [16]


> А критическую секцию можно использовать внутри процедур

Можно. TThreadList так и делает, например.


Miralex   (2005-01-18 12:49:00) [17]


> Digitman

А критическую секцию можно использовать внутри процедур или же надо использовать опасную процедуру внутри критической секции?


Digitman   (2005-01-18 12:46:00) [18]

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

КС.Enter;
try
.. что-то там, не важно что ..
finally
КС.Leave;
end;


Miralex   (2005-01-18 12:40:00) [19]


> огромная куча несуразностей, некорректностей и т.д. и т.п.

где например?


Digitman   (2005-01-18 12:36:00) [20]


> Miralex


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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо