QObject (QPlainTextEdit) и проблемы многопоточности - PullRequest
7 голосов
/ 20 января 2010

Я сейчас пытаюсь научиться работать в сети с Python asyncore и pyqt4.

Я кодировал небольшой сервер, который в основном прослушивает какой-либо порт и повторно отправляет все сообщения, которые он получает отправителю.

Поскольку оба qts QApplication.exec_() и asyncore.loop() являются функциями, которые никогда не возвращаются, я не смог запустить их обоих в одном потоке, поэтому я смотрел asyncore.loop() в отдельном потоке демона.

Всякий раз, когда мой класс сервера (производный от asyncore.dispatcher) устанавливает или сбрасывает соединение, или отправляет / получает сообщение, он вызывает методы моего класса окна (производного от QtGui.QMainWindow), который отображает информацию в QPlainTextEdit.

Но текст не виден, если вы не пометите текст мышью.

В консоли Python отображается следующее сообщение об ошибке:

QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)

Я читал на одном форуме, что это может быть вызвано вызовом qt-функций из другого потока, и что использование сигналов и слотов вместо простого вызова функций может решить проблему, но я пробовал сигналы также, и я все еще получаю эта ошибка.

Итак, (если это действительно является причиной моих проблем), как правильно вызывать методы объекта qt из другого потока?

РЕДАКТИРОВАТЬ Подробнее: вызов asyncore.loop () находится в дочернем потоке, и он не блокируется, а только во время выполнения asyncore.loop () мой серверный класс (asyncore.dispatcher) может работать в сети. Итак, во время выполнения asyncore.loop () методы моего класса Server ARE вызываются asyncore.loop () (= дочерний поток), и в этих попытался передать сигналы классу окна, запущенному в основном потоке

РЕДАКТИРОВАТЬ: Похоже, я получил это работает сейчас, у меня были некоторые ошибки в моем коде, все работает как задумано с сигналами.

РЕДАКТИРОВАТЬ: маленький пример: http://paste2.org/p/635612 (мертвая ссылка)

1 Ответ

10 голосов
/ 21 января 2010

Похоже, вы пытаетесь получить доступ к классам QtGui из потока, отличного от основного потока. Как и в некоторых других инструментах GUI (например, Java Swing), это не разрешено. С веб-страницы Threads и QObjects :

Хотя QObject является реентерабельным, графический интерфейс классы, особенно QWidget и все его подклассы, не реентерабельные. Oни можно использовать только из основного потока.

Решение состоит в том, чтобы использовать сигналы и слоты для связи между основным потоком (где живут объекты GUI) и дополнительными потоками. По сути, вы излучаете сигналы в одном потоке, которые доставляются объектам QO через другой поток. Страница, на которую я ссылался выше, хорошо обсуждает это. На самом деле, весь раздел по Thread Support в Qt является хорошим чтением.

Одна потенциальная проблема, с которой вы можете столкнуться, заключается в том, что обычно для получения полной поддержки сигналов и слотов, работающих в потоках, вам необходимо запустить цикл обработки событий в дочернем потоке, используя QThread::exec() (или эквивалент PyQt), чтобы сигналы могут быть доставлены в слоты в QObjects, которые там живут. В вашем случае звучит так, будто вы делаете блокирующий вызов на asyncore.loop(), что помешает вам сделать это. Но если вам нужно излучать сигналы только в одном направлении (от дочернего потока до виджетов в основном потоке), я не думаю, что у вас возникнут проблемы.

...