Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2003.05.12;
Скачать: CL | DM;

Вниз

Непонятный глюк с TThread.   Найти похожие ветки 

 
Zilog ©   (2003-04-28 10:37) [0]

Народ! Помогите разобраться с глюком. :(
В общих чертах - алгоритм работы такой: создаётся поток, для передачи данных через GSMмодем. При запуске потока идёт регистрация в сети, дозвон. Далее функцией
Manager.GetRemoteData(Manager.SelectedStation);
Получаю данные с удалённого объекта. Всё в порядке.
Далее идёт цикл:
while not Terminated do Synchronize(DoWork);
- выполнение процедуры DoWork пока поток живой. В этой процедуре проверка булевских переменных, при истинности которых выполняется некое условие, в том числе и вышеуказанная процедура получения данных. Состояние этих переменных меняет пользователь, например при нажатии на кнопку "обновить".

Дык вот, вся проблема в том, что из процедуры DoWork процедура
Manager.GetRemoteData(Manager.SelectedStation);
отказывается работать. Глюк получается в мете передачи данных - т.е. я выполняю transmit, т.е. делаю запрос, далее ожидание ответа, которого нет... Таймаут я пока не сделал, поэтому происходит мёртвый зависон (но это уже не важно).

Как думаете, почему функция
Manager.GetRemoteData(Manager.SelectedStation);
отказывается работать из DoWork, если она прекрасно работает из других мест?...



type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure Disconnect;
procedure DoWork;
end;

procedure TMyThread.Execute;
begin
Manager.Modem.ViewCmdLog(false);
Manager.Modem.SetDelay(250,100);
if not Manager.Modem.NetworkRegistration("....") then Disconnect;
if not Manager.Modem.Dial(TStation(Manager.SelectedStation).Param.Phone) then Disconnect;
Manager.GetRemoteData(Manager.SelectedStation);

while not Terminated do Synchronize(DoWork);

end;
procedure TMyThread.Disconnect;
begin
Status(stDm,"no carrier");
ExitThread(0);
end;

procedure TMyThread.DoWork;
begin
if Manager.RefreshStation then Manager.GetRemoteData(Manager.SelectedStation);
if Manager.Disconnect then Disconnect;
end;


 
Digitman ©   (2003-04-28 10:51) [1]

все, что делается у тебя в DoWork, исполняется в осн.код.потоке.

в этом случае совершенно непонятно, почему самый первый вызов Manager.GetRemoteData() ты делаешь в доп.код.потоке, а все последующие - в основном.


 
han_malign ©   (2003-04-28 10:54) [2]

Поясни мне глупому, зачем тебе поток, если основной рабочий цикл ты делаешь в контексте главного потока приложения (Synchronize деалает именно это), при этом, судя по всему, не оставляя Manager-у времени на обработку???


 
REA ©   (2003-04-28 10:55) [3]

Synchronize выполняется в контексте основного потока и, вероятно, не выполняется какое либо событие/условие, которое создается тоже в основном потоке. Кроме того такой код приведет к некоторому ухудшению быстродействия. Для синхронизации потоков часто бывает достаточно объектов синхронизации (CriticalSection и т.п.)


 
Zilog ©   (2003-04-28 11:00) [4]

Synchronize помениял на:
while not Manager.Disconnect do begin
DoWork;
end;
всё работает, только в этом случае анимация основного потока начинает тормозить, мля.... Что делать то?


 
Digitman ©   (2003-04-28 11:07) [5]


> Что делать то?


полностью переделать TMyThread (исключив из него совершенно бестолковую в дан.случае логику синхронизации с осн.потоком) - наилучший выход


 
Snap ©   (2003-04-28 11:07) [6]

В этом компоненте никак с событиями нельзя сделать? Если нет то я думаю торможение можно убрать только одним сособом- уменьшением приоритета дополнительного потока.


 
Zilog ©   (2003-04-28 11:10) [7]

>>бестолковую в дан.случае логику синхронизации с осн.потоком
уже убрал
>> В этом компоненте никак с событиями нельзя сделать?
Не-а, а приоритет доп. потока уменьшить никак не могу. Это очень критично - GSM связь, секунды идут....
А тормозит while.... чем его заменить можно?


 
Verg ©   (2003-04-28 11:11) [8]

Дык DoWork жрет почти полностью тайм-слот данного приоритета.

Попробуй хоть так пока:

while not Manager.Disconnect do begin
DoWork;
sleep(0);
end;


А вообще, если поток чего-нибудь должен ждать по смыслу происходящего, то надо применять либо waitfor... либо peekmessage/getmessage, либо на худой конец sleep()


 
Snap ©   (2003-04-28 11:13) [9]

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


 
Digitman ©   (2003-04-28 11:14) [10]

while not Terminated and GetMessage(..) do
Dispatch(..);


 
Snap ©   (2003-04-28 11:16) [11]

2Verg
А разве слип не тормозит процесс? Я имею ввиду что паузу то он далет, но делает ли её правильно?

2Zilog
Мне кажется для твоей задачи также подходит таймер. Если ДуВорк выполняется не очень долго, то с таймером можно будет убрать почти всё торможение


 
Verg ©   (2003-04-28 11:23) [12]


> А разве слип не тормозит процесс? Я имею ввиду что паузу
> то он далет, но делает ли её правильно?


Тормозит конечно. Только не процесс, а поток, давая тем самым возможность больше работать другим потокам данного приоритетного кольца (в том числе и основному потоку твоего процесса) и вообще работать потокам нижних колец.
Когда твой поток чегонибудь ждет, например, ответа от модема по комуникационному порту, можно (и даже нужно) применить overlapped IO с ожиданием события функцией WaitForSingleObject события в структуре overlapped.

Джефри Рихтер, по-моему хорошо об этой кухне писал в "Windows для профессионалов".


 
Snap ©   (2003-04-28 11:24) [13]

2Verg

спасибо за справку


 
Zilog ©   (2003-04-28 11:29) [14]

to Verg:

Спасибо, вот это помогло:
у меня было так же, после Synchronize, тока слипа не было.

while not Manager.Disconnect do begin
DoWork;
sleep(0);
end;


 
Digitman ©   (2003-04-28 11:34) [15]

а куда ж теперь делся повторный вызов GetRemoteData() при условии RefreshStation = True ?


 
Zilog ©   (2003-04-28 11:37) [16]

никуда не делася... вот он: %)

procedure TMyThread.DoWork;
begin
if Manager.RefreshStation then Manager.GetRemoteData(Manager.SelectedStation);
if Manager.Disconnect then Disconnect;
end;


 
REA ©   (2003-04-28 11:39) [17]

Terminated потерялся куда-то...


 
Digitman ©   (2003-04-28 11:42) [18]

ну так ты объясни мне, тундре, на кой шут такой доп.код.поток нужен, если GetRemoteData (в теле DoWork) все равно будет у тебя выполняться в осн.код.потоке ?)


 
Zilog ©   (2003-04-28 11:50) [19]

Почему в основном, то???


 
Zilog ©   (2003-04-28 11:52) [20]

Если бы в основном выполнялось, тогда бы приложение не реагировало несколько секунд ни на какие действия пользователя... Передача данных занимает несколько секунд, а мне надо при этом сохранять активность приложения к действиям пользователя + анимация работает... незя чтоб тормозило....


 
Snap ©   (2003-04-28 11:55) [21]

Ну так есть же Application.processmessages


 
Digitman ©   (2003-04-28 11:56) [22]

надо понимать, Synchronize ты намеренно исключил из кода ?
в таком случае - что есть Manager ? какого класса объект ?


 
Zilog ©   (2003-04-28 12:04) [23]

Manager - моего класса объект.


 
Anatoly Podgoretsky ©   (2003-04-28 12:07) [24]

А моего класса объект, какого класса объект ?


 
Zilog ©   (2003-04-28 12:10) [25]

type TManager = class


 
Digitman ©   (2003-04-28 12:21) [26]

Manager.RefreshStation
Manager.SelectedStation;
Manager.Disconnect;

это что, поля класса или функциональные методы класса ?
осн.поток обращается к ним ?


 
Zilog ©   (2003-04-28 12:28) [27]

осн. поток их меняет, а обсуждаемые по ним принимает решения.

Manager.RefreshStation - boolean
Manager.SelectedStation - pointer;
Manager.Disconnect - boolean;



 
Digitman ©   (2003-04-28 12:35) [28]

вот и "чеши репу", думая над вопросом :

что произойдет с доп.потоком, если осн.поток установит св-во Manager.SelectedStation = nil до того как установит Disconnect = False


 
Zelius ©   (2003-04-28 12:46) [29]

Имхо, явно не хватает объекта синхронизации, например Event"а!
что-то типа

var Event: TEvent;
...........
while NOT Terminated do
begin
case Event.WaitFor(3000) of
wrSignaled: DoWork;
wrTimeout: ;// Some work by timeout
else
// error
Terminate;
end;
end;


 
Zilog ©   (2003-04-28 13:40) [30]

что произойдет с доп.потоком, если осн.поток установит св-во Manager.SelectedStation = nil до того как установит Disconnect = False

Ничего не произойдёт. Manager.SelectedStation устанавливается таким образом, что нила там не быват :)


 
Digitman ©   (2003-04-28 14:08) [31]

а что произойдет, если осн.поток установит Manager.Disconnect = True в то время как доп.поток уже выполняет Manager.GetRemoteData ?


 
Zilog ©   (2003-04-28 14:11) [32]

Исходя из этого

procedure TMyThread.DoWork;
begin
if Manager.UpdateStation then Update;
if Manager.RefreshStation then Refresh;
if Manager.Disconnect then Disconnect;
end;

получается, что пока идёт Manager.GetRemoteData (ф-я Refresh), Manager.Disconnect не обрабатывается. Manager.Disconnect обрабатывается в последнюю очередь, после завершения основных работ.
Так что ничего не произойдёт, всё произойдёт в штатном режиме :)


 
Digitman ©   (2003-04-28 14:22) [33]

итак, цитирую твою последнюю редакцию

// цикл выполняется в доп.потоке
while not Manager.Disconnect do begin
DoWork;
sleep(0);
end;

procedure TMyThread.DoWork;
begin
if Manager.UpdateStation then Update;
if Manager.RefreshStation then Refresh; // в момент выполнения Refresh осн.поток установил Manager.Disconnect !!!!!
if Manager.Disconnect then Disconnect;
end;

что скажешь ?)


 
Zilog ©   (2003-04-28 14:25) [34]

%))) Да, будет глюкан :)))
Значит сделаю участок DoWork как критический. Ели он выполняется, никаких дисконнектов...


 
Zilog ©   (2003-04-28 14:29) [35]

Погоди!!.. Не будет никакого глюка. Нормально всё. Если он в "// в момент выполнения Refresh осн.поток установил Manager.Disconnect !!!!!
"
То всё хорошо, следующей процедурой - он спокойненько выйдет из потока...


 
Digitman ©   (2003-04-28 14:30) [36]


> Zilog



> %))) Да, будет глюкан :)))


да хренью ты занимаешься)

если Manager - некий класс, отвечающий искл-но за транспорт, то самый простой выход - создавать его прямо в доп.потоке, тогда и никакой "DoWork как критический" не потребуется)


 
Digitman ©   (2003-04-28 14:32) [37]


> Если он в "// в момент выполнения Refresh осн.поток установил
> Manager.Disconnect !!!!!


поэтому я и спросил : Disconnect - это МЕТОД ? или ПОЛЕ ?
ты же не удосужился ответить)))


 
Zilog ©   (2003-04-28 14:34) [38]

Manager.Disconnect - свойство моего класаа
Disconnect - метод потока.



 
Digitman ©   (2003-04-28 14:50) [39]


> Zilog



> Manager.Disconnect


Ты русский язык понимаешь ?
Manager.Disconnect - это св-во, непосредственно модифицирующее ПОЛЕ класса Manager или это св-во, вызывающее МЕТОДЫ класса Manager ? разные ж совершенно вещи !


Опять же TMyThread.Disconnect - это ПОЛЕ или МЕТОД ? И какое отношение TMyThread.Disconnect имеет к вопросу ? Нигде в приведенных фрагментах кода даже не упоминается !




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

Текущий архив: 2003.05.12;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.014 c
1-34472
unreger
2003-04-29 08:43
2003.05.12
множества


6-34535
alex2003
2003-03-14 06:12
2003.05.12
Отправка SMS


7-34633
AlexPro_
2003-03-14 17:21
2003.05.12
Выключение компа из-под Win2000 Adv Serv


6-34532
JeskelA
2003-03-15 10:52
2003.05.12
Работа с Ethernet протоколом


1-34406
Striker
2003-04-30 12:08
2003.05.12
как из listbox1 перенести выделеные строки в listbox2 ?