Функции блокировки Qt Socket, необходимые для запуска в QThread, где они были созданы.Есть ли способ пройти мимо этого? - PullRequest
4 голосов
/ 03 марта 2011

Заголовок очень загадочный, вот так!

Я пишу клиент, который ведет себя очень синхронно.Из-за структуры протокола и сервера все должно происходить последовательно (отправка запроса, ожидание ответа, ответ службы и т. Д.), Поэтому я использую блокирующие сокеты.Вот где приходит Qt.

В моем приложении у меня есть поток GUI, поток обработки команд и поток движка сценариев.Я создаю QTcpSocket в потоке обработки команд, как часть моего класса Client.Класс Client имеет различные методы, которые сводятся к записи в сокет, чтению определенного количества байтов и возвращению результата.

Проблема возникает, когда я пытаюсь напрямую вызывать методы Client из потока механизма сценариев,Сокеты Qt случайным образом истекают , и при использовании отладочной сборки Qt я получаю следующие предупреждения:

QSocketNotifier: socket notifiers cannot be enabled from another thread
QSocketNotifier: socket notifiers cannot be disabled from another thread

Каждый раз, когда я вызываю эти методы из потока обработки команд (где был создан клиент)), Я не получаю эти проблемы.

Чтобы просто сформулировать ситуацию:

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

Кто-нибудь еще сталкивался с этим?Пути вокруг этого?

Заранее спасибо.

1 Ответ

4 голосов
/ 03 марта 2011

Я предполагаю, что вы используете QThread для операций с потоками. Если это так, вы можете либо: а) использовать соединения в слоте с очередями ; или b) явно использовать цикл событий QThread, создав собственный тип события, опубликовав это событие в вашем скриптовом движке, а затем попросив клиентский класс обработать эти события.

пример для а)

class ClientThread : public QThread
{
    ..stuff..
public slots:
   waitForReadyRead();
};

class ScriptEngineThread : public QThread
{
    ..other stuff..
 signals:
    void requestWaitForReadyRead();
};

// In the ScriptEngineThread implementation...
ScriptEngineThread::setupClient()
{
   connect(this, SIGNAL(requestWaitForReadyRead()),
      client_, SLOT(waitForReadyRead()),
      Qt::QueuedConnection);
}

Затем, когда вы хотите выполнить операции с сокетом, просто emit ScriptEngineThread::requestWaitForReadyRead();. Основная трудность, я полагаю, заключается в том, что вам нужен поток сценариев для ожидания выполнения какой-либо операции с сокетом. В этом случае вам придется передавать сигналы назад и вперед между потоками, вызывая некоторую циклическую зависимость.

Для альтернативы b это потребует немного больше работы по кодированию, но вы можете:

  • Создайте свои собственные подклассы QEvent
  • Создайте класс для работы в качестве посредника, публикуя и обрабатывая каждое из ваших QEvents и передавая сигналы для связи с потоками - каждый поток может иметь экземпляр этого
  • Подключите клиент и обработчик сценариев к сигналам событий, которые ему небезразличны.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...