Как сделать QObject :: moveToThread () при использовании QThreadPool? - PullRequest
7 голосов
/ 27 июня 2010

Я создаю небольшой многопоточный веб-сервер. QTcpSockets выбираются в главном потоке, а затем передаются QtConcurrent в QThreadPool, который в конечном итоге обрабатывает данные и отправляет ответ.

Моя проблема в том, что сокет создается в главном потоке и обрабатывается в другом. Это вызывает ошибки при попытке записи в сокет:

socket->write(somedata);

QObject: Невозможно создать дочерние объекты для родитель, который находится в другой теме. (Родитель QNativeSocketEngine (0x608330), родительский поток - QThread (0x600630), текущий поток - QThread (0x505f60)

Чистым способом было бы переместить объект сокета в поток обработки, используя

socket->moveToThread(QThread::currentThread()).

Это, однако, можно вызывать только в потоке, в котором был создан объект. Кроме того, сокет имеет в качестве родительского объекта QTcpServer, так что moveToThread () в любом случае завершится ошибкой (парентные объекты не могут переключать потоки).

Как я могу переместить объект в QThread :: currentThread () в коде, который запускается пулом потоков? Кроме того, как я могу записать в сокет вне потока, он был создан?

Ответы [ 3 ]

4 голосов
/ 16 июля 2010

Расширить QTcpServer, переопределить incomingConnection(int socketDescriptor) и передать дескриптор сокета потокам в пуле. Пусть QRunnable создаст QTcpSocket из дескриптора и запустит цикл обработки событий для получения сигналов этого сокета.

0 голосов
/ 02 января 2015

Я бы также согласился, что перехват incomingConnection(int) и создание сокета в рабочем потоке - вот путь.

Но ваша проблема была более фундаментальной, поэтому позвольте мне показать альтернативу, чторешает общую проблему (перемещение произвольных QObject s в потоки в пуле потоков):

  1. В основном потоке: отделить сокет от любого потока:

    сокет-> moveToThread (nullptr);

    Это приостановит обработку событий сокета.Затем передайте его в QtConcurrent.

  2. В функции, выполняемой в пуле потоков, вы можете теперь вызвать

    socket-> moveToThread (QThread:: currentThread ());

    Это перезапустит обработку событий.

Если повезет, сокет будет перерегистрировать свои уведомители сокета в рабочем потокеснова цикл обработки событий, и вы можете обслуживать соединение от работника.

Здесь есть два важных предостережений , хотя:

  • Не следует ставить блокирующие задачи в глобальном пуле потоков (QThreadPool::globalInstance()).Как следует из названия функции, этот экземпляр пула потоков является глобальным ресурсом, общим для всех пользователей QtConcurrent, и блокировка его рабочих потоков в лучшем случае уменьшает емкость (а значит, пропускную способность) пула, а в худшем -dead-lock.
  • Если вы используете цикл обработки событий для рабочих потоков (из-за первой точки не использовать синхронный API QTcpSocket, вам нужно вызвать QThread::currentThread()->exec(), чтобы запустить его,Это, однако, является блокирующим вызовом и для планировщика пула потоков рабочий будет выглядеть занятым, поэтому он не будет выполнять ему больше задач (т. Е. QRunnable s).

Если вы на самом делеЕсли вы хотите реализовать многопоточный tcp-сервер, вам нужно будет создать свой собственный пул потоков.

0 голосов
/ 27 июня 2010

Брэдли Хьюз (Bradley Hugues) написал пост в Qt Labs, в котором говорится об этой теме, может быть, это вам немного поможет!

http://blog.qt.digia.com/2010/06/17/youre-doing-it-wrong/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...