Поток Python постоянно зависает вся программа?
Прежде всего, я должен сказать, что я не очень разбираюсь в программировании на Python, как на других языках. Я очень (слишком) раздражен поиском других путей решения, поэтому заранее благодарю вас за вашу помощь.
Я люблю делать игры на Roguelike в свое свободное время, поэтому я попробовал множество способов сделать свои собственные реализации "движка" и собственные движки для своих игр с использованием C++, C, C#, HTML5 и т. Д. Я никогда раньше не работал с LibTCOD, потому что я никогда не мог заставить его работать в C++, увы, это мой любимый язык программирования, это проблема, о которой я не буду сейчас говорить, потому что она в потоке C++.
Ужасно, но LibTCOD выглядит великолепно, но в нем слишком мало упоминаний и точной документации, так что я решил сделать это практически в одиночку. В последние дни я сделал небольшой пакет python, чтобы легко управлять функциональностью LibTCOD для python и windows, и сделать основной код игры как можно меньше.
Последняя реализация, которую я попытался добавить, состоит в том, чтобы передать основной игровой цикл в поток, обрабатывая все основные функциональные возможности игры (например, изменения клавиатуры / мыши и обновление экрана), и выполняя его с помощью вызова функции.
Все работает нормально... но не после первого шага цикла, потому что он все зависает и перестает работать.
В основном это проблемный код:
def ioHandler(l):
lastx = 0
lasty = 0
lastk = None
c = 0
noEvent = 0
casted = False
while not tcod.console_is_window_closed():
l.acquire()
try:
tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS|tcod.EVENT_MOUSE,key,mouse)
finally:
l.release()
if mouse.lbutton_pressed:
casted = True
l.acquire()
try:
onClick(mouse, 'left')
finally:
l.release()
if mouse.rbutton_pressed:
casted = True
l.acquire()
try:
onClick(mouse, 'right')
finally:
l.release()
if mouse.cx != lastx or mouse.cy != lasty:
casted = True
l.acquire()
try:
lastx = mouse.cx
lasty = mouse.cy
onMouseMove(mouse)
finally:
l.release()
if key != lastk:
casted = True
l.acquire()
try:
lastk = key
onKeyPress(key)
finally:
l.release()
if not casted: noEvent += 1
l.acquire()
try:
onTickFrame(c+1)
finally:
l.release()
Большинство переменных, используемых там, предназначены для более ясного понимания отладки (даже с "чистой" функцией, она заморозилась), поэтому я должен поместить их туда.
Вышеуказанный def вызывается отсюда:
def main_loop():
l = threading.Lock()
tr = threading.Thread(target=ioHandler, args=(l,))
#tr.daemon=True
tr.start()
Для системы "Событие" я нашел это в интернете:
class Event:
handlers = set()
def __init__(self):
self.handlers = set()
def handle(self, handler):
self.handlers.add(handler)
return self
def unhandle(self, handler):
try:
self.handlers.remove(handler)
except:
raise ValueError("Handler is not handling this event, so cannot unhandle it.")
return self
def fire(self, *args, **kargs):
for handler in self.handlers:
handler(*args, **kargs)
def getHandlerCount(self):
return len(self.handlers)
__iadd__ = handle
__isub__ = unhandle
__call__ = fire
__len__ = getHandlerCount
Как примечание: я работаю с Python 2.7, это единственная версия, которая работает для библиотеки, какой позор.
Я думаю, что система событий может быть главной проблемой. Читая код снова, я думаю, что я должен применить блокировку к условию while, следовательно, ко всему циклу, или это не нужно? Правильно ли установлены замки? или я должен использовать другие методы, чтобы поток работал?
Просто отметим, что все работает нормально, если основной игровой цикл выполняется на основном скрипте без потоков, но все происходит не так, когда вызывается как поток, или даже если это не сам поток, а он вызывается извне, как любая другая функция в пакет, так что это не может быть проблемой библиотеки (я думаю).
Я должен сказать, что я работал только с LibTCOD в Python, так как я не могу заставить его работать (по крайней мере, на Windows) только на нем. Если это поможет, я видел, что код для библиотеки Python является просто "связующим звеном" с исходной библиотекой C, поэтому понимать код Python не составляет особого труда. Что касается последнего утверждения, я думаю, что это проблема и для потоков Python, или я ошибаюсь? если я могу что-то сделать для исправления нити, пожалуйста, помогите мне!
Спасибо вам всем! Надеюсь, я не наскучил вам своим разговором.
1 ответ
В вашем примере было достаточно пропущенного, и я не смог запустить его своевременно, поэтому у меня нет для вас известного решения, но у меня есть некоторые предложения:
- Если тот же поток будет освобождать блокировку, которая его получила, я предлагаю использовать RLock() вместо Lock ()
l = threading.RLock()
- Чтобы сделать код чище и избежать ошибок, я предлагаю использовать менеджер контекста, который обеспечивает блокировка:
Вместо:
l.acquire():
try:
tcod.sys_check_for_event(
tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse)
finally:
l.release()
Пытаться:
with l:
tcod.sys_check_for_event(
tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse)
- Что касается вопроса о том, что еще должно быть заблокировано. Трудно ответить без понимания всех структур данных, но в целом все, что будет использоваться в более чем одном потоке, должно быть заблокировано.