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