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

Вниз

Виснет программа! CriticalSection или ?   Найти похожие ветки 

 
Miralex ©   (2005-01-18 11:54) [0]

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

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

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) из потока.

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

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


 
TUser ©   (2005-01-18 12:14) [1]

ИМХО, тут гораздо лучше использовать Synchronize.

> Критических секций в потоке нету, так как они внутри класса
> перекрывают все!

То, что в одном потоке уже есть критические секции вовсе не означает, что в другом потоке их не должно быть. Точнее - означают как раз обратное.


 
Miralex ©   (2005-01-18 12:23) [2]

Да но по сути метод Synchronize достаточно медленнее чем CriticalSection.


> ИМХО, тут гораздо лучше использовать Synchronize.

Почему лучше?


 
Digitman ©   (2005-01-18 12:36) [3]


> Miralex


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


 
Miralex ©   (2005-01-18 12:40) [4]


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

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


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

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

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


 
Miralex ©   (2005-01-18 12:49) [6]


> Digitman

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


 
TUser ©   (2005-01-18 12:52) [7]


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

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


 
Miralex ©   (2005-01-18 12:56) [8]

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

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

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


 
Digitman ©   (2005-01-18 13:11) [9]


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


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


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


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

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

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


 
Miralex ©   (2005-01-18 13:18) [10]


> Digitman

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

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


 
Digitman ©   (2005-01-18 13:39) [11]


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


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


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


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


 
Miralex ©   (2005-01-18 14:16) [12]

Полно переменных которые мне необходимо будет использовать и потоке. Ну например:
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 14:22) [13]


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


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


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


> AddtoDebugMemo


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

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


 
Miralex ©   (2005-01-18 14:32) [15]

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

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";

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


 
Miralex ©   (2005-01-18 14:34) [16]


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


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


 
Digitman ©   (2005-01-18 14:39) [17]


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


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


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


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


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


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


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


 
Digitman ©   (2005-01-18 14:50) [19]


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


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


 
Miralex ©   (2005-01-18 14:55) [20]

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


 
Digitman ©   (2005-01-18 15:13) [21]


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


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

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

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


 
Miralex ©   (2005-01-18 15:30) [22]

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



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

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

Наверх




Память: 0.51 MB
Время: 0.037 c
6-1100412396
focor
2004-11-14 09:06
2005.01.30
HTML_API


3-1103889364
Tomkat
2004-12-24 14:56
2005.01.30
BackUP/Restore MS SQL


6-1100494168
Mr
2004-11-15 07:49
2005.01.30
Передача TStream


1-1106035263
Алексей34
2005-01-18 11:01
2005.01.30
TDBGrid и индекс выбранное строки


14-1103561190
Cerberus
2004-12-20 19:46
2005.01.30
Встерча в самаре





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