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

Вниз

Непонятный глюк с 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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.005 c
14-34560
Мысык
2003-04-23 10:38
2003.05.12
Эхом гонга


3-34354
Askik
2003-04-18 15:44
2003.05.12
Как заставить ADOQuery не скачивать все записи набора данных?


1-34502
fighter@str
2003-04-29 17:36
2003.05.12
Delphi+Реестр


4-34649
Nick Denry
2003-03-11 20:59
2003.05.12
Меню


1-34407
Феникс
2003-04-29 18:11
2003.05.12
Проблема с TImageList





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