Проблема с потоками

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Проблема с потоками

Сообщение unC0Rr » 06.05.2007 21:52:24

Приветствую! При написании игры столкнулся с проблемой. В процессе работы программы создаётся новый поток вызовом BeginThread, запоминается его хэндл. Через некоторое время требуется закончить поток, для чего выставляется переменная-флаг и происходит ожидание окончания потока вызовом WaitForThreadTerminate с таймаутом 5000. Собственно проблема: поток узнаёт по флагу, что пора закругляться, завершает работу, но! WaitForThreadTerminate в основном потоке не обрабатывает момент завершения потока. Собственно, в процессе работы получил такой лог:
Код: Выделить всё
calling WaitForThreadTerminate (handle=1420 ticks=2228)
Thread finishing (handle=1420 ticks=2267)
WaitForThreadTerminate returned 258 (ticks=7228)

Откуда видно, что ожидание происходит с правильным хэндлом, поток правильно отрабатывает момент завершения, но WaitForThreadTerminate этого не замечает и возвращает статус WAIT_TIMEOUT по истечении таймаута.
Надеюсь на помощь в разрешении ситуации!

ОС WinXP, компилятор FPC 2.0.4
unC0Rr
новенький
 
Сообщения: 59
Зарегистрирован: 02.02.2006 03:44:44

Сообщение Sergei I. Gorelkin » 07.05.2007 02:15:32

Странно это как-то...
У меня нет под руками исходников RTL 2.0.4, но в 2.1.3 функция WaitForThreadTerminate под виндой вызывает WaitForSingleObject(handle, timeout). Можно попробовать вызвать непосредственно...
Еще можно взять отладчик и убедиться, что поток действительно завершается, а не пишет "завершаюсь" и застревает где-нибудь в логгере. А также что WaitForThreadTerminate вызывается из правильного (т.е. основного) потока.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение unC0Rr » 07.05.2007 12:50:22

То и странно, что единственный вариант, при котором такое возможно - это незавершение потока в действительности. Но дело в том, что логирование - это последняя операция в потоке, затем идёт EndThread. В логгере поток также не застревает, это проверено. WaitForThreadTerminate вызывается, конечно, из правильного потока, перепутать сложно - потоков всего два. Не знаю, что и подумать.
В принципе, есть ещё одна операция в RTL при выходе из потока - освобождение ThreadVars (SysReleaseThreadVars). Возможно ли застревание в нём? Единственная строка в этой процедуре
Код: Выделить всё
LocalFree(TlsGetValue(tlskey));
unC0Rr
новенький
 
Сообщения: 59
Зарегистрирован: 02.02.2006 03:44:44

Сообщение Sergei I. Gorelkin » 07.05.2007 16:23:24

unC0Rr писал(а):В принципе, есть ещё одна операция в RTL при выходе из потока - освобождение ThreadVars (SysReleaseThreadVars). Возможно ли застревание в нём? Единственная строка в этой процедуре
Код: Выделить всё
LocalFree(TlsGetValue(tlskey));


Ну, это легко проверяется заменой EndThread на Windows.ExitThread. Кроссплатформенность, естественно, при этом идет лесом, и переменные не освобождаются, но ценное знание получается...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение unC0Rr » 07.05.2007 21:54:31

Применение Windows.ExitThread, кажется, помогло (точно не могу сказать, нужно длительное тестирование, т.к. ситуация не 100%-но воспроизводимая). Утечек памяти при этом нет, ThreadVars в программе не используются.
Ещё интересная деталь: при проявлении проблемы лишних потоков не остаётся (в диспетчере задач после запуска программы 6 потоков, при создании дополнительного 7, после этого глюка опять 6), т.е. поток всё же завершается, по всей видимости. Я в тотальном недоумении.
В принципе, можно добавить отдельный случай для винды, но при этом нет гарантии, что на других платформах всё будет нормально.
unC0Rr
новенький
 
Сообщения: 59
Зарегистрирован: 02.02.2006 03:44:44

Сообщение Sergei I. Gorelkin » 07.05.2007 22:46:13

ThreadVars используются в самой RTL, так что теоретически надо их освобождать, даже если их нет в программе. Поскольку они выделяются с помощью LocalAlloc/LocalFree, а не GetMem/FreeMem, модуль heaptrc утечку не покажет.
Еще нюанс - Delphi использует для ожидания не WaitForSingleObject, а MsgWaitForMultipleObjects, чтобы основной поток мог обрабатывать (точнее, даже не обрабатывать, а извлекать из очереди) оконные сообщения. Тоже можно попробовать.
А другие платформы - это вообще отдельная песня...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение unC0Rr » 07.05.2007 23:00:09

Странно всё это... WaitForSingleObject в принципе то, что надо, 10-50 мс задержки отрисовки пользователь не заметит. В RTL вроде всё правильно написано, только ThreadVars смущают. Память смотрел опять же через диспетчер задач. Пишу кроссплатформенную игру, не хотелось бы костыли лепить :(
unC0Rr
новенький
 
Сообщения: 59
Зарегистрирован: 02.02.2006 03:44:44

Сообщение unC0Rr » 07.05.2007 23:11:08

Оп-па... оказывается, windows.ExitThread всё-таки не помогает. Всё, теперь совсем ничего не понятно... :(
unC0Rr
новенький
 
Сообщения: 59
Зарегистрирован: 02.02.2006 03:44:44

Re: Проблема с потоками

Сообщение VirtUX » 09.12.2008 11:53:28

Есть-ли возможность на произвольном этапе выполнения программы узнать - существует-ли еще поток или нет?
Запускаю таким образом:
Код: Выделить всё
PThread := MyThread.Create(true);
PThread.FreeOnTerminate := true;
PThread.Priority := tpNormal;
PThread.Resume;
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Проблема с потоками

Сообщение Sergei I. Gorelkin » 09.12.2008 17:36:11

Без содействия со стороны самого потока - нельзя. Нужно либо назначать обработчик OnTerminate, либо хотя бы не устанавливать FreeOnTerminate - тогда объект останется жив и у него можно будет вызвать WaitFor.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Проблема с потоками

Сообщение Михаил Крамер » 09.12.2008 18:18:29

А если вместо флагов на завершение использовать симафоры и события (Event)?
Михаил Крамер
новенький
 
Сообщения: 73
Зарегистрирован: 08.02.2008 14:26:40

Re: Проблема с потоками

Сообщение Sergei I. Gorelkin » 09.12.2008 19:31:59

В любом случае где-то в коде потока нужно будет устанавливать событие/сигналить семафор.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4

Рейтинг@Mail.ru