2014-12-04 11 views
1

У меня есть интересная проблема для решения. Я использую Qt 5 для одного из моих проектов для чтения информации в сети. Я читаю устройства Modbus и прочее, но реальная проблема возникает, когда сеть недоступна.Qt Замораживание интерфейса на фоновой задаче

Интерфейс замерзает, и я не могу взаимодействовать с ним. Сетевые материалы выполняются в отдельном потоке, или это то, что я думаю. Вот некоторые пример кода:

class TwidoDevice : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit TwidoDevice 
........ And some useful code 

Использование (главный интерфейс) в классе Window.cpp является:

L1Thread = new QThread(); 
L1Thread->start(); 
L1TWD = new TwidoDevice(L1TWD_settings, 
         L1TWD_Name, 
         PercentRegisters, 
         TotalsRegisters, 
         db, 1); 
L1TWD->moveToThread(L1Thread); 
connect(this, SIGNAL(startReading()), L1TWD, SLOT(startFired()), Qt::DirectConnection); 

В этом коде startFired() начать чтение устройств в сети.

В некоторой другой функции в Window.cpp:

emit startReading() 

Когда этот код выполняется интерфейс замерзает, даже если я переместил L1TWD объект QThread.

Когда я пытаюсь отладить его с помощью встроенного отладчика в QtCreator, я не могу понять, был ли объект перемещен или нет, и почему интерфейс был заморожен во время сетевого вызова.

Неужели кто-то столкнулся с одной и той же проблемой и как решить эту проблему?

Спасибо, что потратили время на чтение моего вопроса!

+0

Вы пытались подключиться (это, SIGNAL (startReading()), L1TWD, SLOT (startFired())); '? Пожалуйста, используйте currentThread, чтобы распечатать это, чтобы убедиться, что вы правильно переехали. – lpapp

ответ

4

Это главная проблема:

подключения (это, SIGNAL (startReading()), L1TWD, SLOT (startFired()), Qt :: DirectConnection);

Вы подключаете приемник и отправитель в разных потоках с прямым подключением, которое блокирует пользовательский интерфейс. Учитывая, что выполнение вашего слота застряло, это ожидается. У вас есть как минимум два вопроса для решения.

  • Используйте соединение по умолчанию, которое не будет блокироваться нитями, только внутри одного потока.Таким образом, вы писали бы что-то вроде этого:

подключения (это, SIGNAL (startReading()), L1TWD, SLOT (startFired()));

  • Во-вторых, вы можете убедиться, что ваш поток не застревают, когда есть какая-то проблема «сеть».

Для целей отладки, пожалуйста, распечатайте текущий поток, когда имеющий такого рода проблем, пронизывающих использованием the following methods:

[статические] QThread * QThread :: currentThread()

Возвращает указатель на QThread, который управляет текущим исполняемым потоком.

и this:

[статические] Qt :: HANDLE QThread :: currentThreadId()

Возвращает дескриптор потока текущего выполняемого потока.

Предупреждение: дескриптор, возвращаемый этой функцией, используется для внутренних целей и не должен использоваться в любом прикладном коде.

Предупреждение. В Windows возвращаемое значение является псевдо-дескриптором для текущего потока. Он не может использоваться для численного сравнения. то есть эта функция возвращает DWORD (идентификатор Windows-Thread), возвращаемый функцией Win32 getCurrentThreadId(), а не HANDLE (Windows-Thread HANDLE), возвращаемый функцией Win32 getCurrentThread().

+0

Спасибо! Вы дали лучший ответ. Я уверен, что с моим кодом много проблем, но я все еще новичок. То, как вы предлагали работать, я думаю, что moc делает что-то за сценой и создает проблемы для меня. – melanholly

+1

@melanholly: печать текущих потоков приблизит нас к решению вашей основной причины. – lpapp

+0

@melanholly: Я думаю, что ваша настоящая проблема может быть [это] (http://doc-snapshot.qt-project.org/qt5-5.4/qobject.html#moveToThread): 'Объект нельзя переместить, если он имеет parent'. Вы не указали конструктор 'TwidoDevice', но я предполагаю, что вы создали родителя с одним из ваших аргументов. – lpapp

4

Вы используете для своего подключения Qt::DirectConnection, что означает, что слот вызывается сразу, то есть в том же потоке, что и при срабатывании сигнала. Вы можете посмотреть the documentation for ConnectionType. То, что вы хотите использовать, вероятно, Qt::QueuedConnection, которое выполняет слот в потоке принимающего объекта.

Наилучший способ, хотя, как и lpapp pointet, - дать Qt решить, что лучше, и просто использовать Qt::AutoConnection, который по умолчанию. Он будет использовать QueuedConnection, если сигнальные и принимающие потоки разные, а DirectConnection - в противном случае.

+1

Было бы лучше использовать auto (default), чтобы быть справедливым. – lpapp

+0

Тип подключения по умолчанию (авто) - это то, что не работает для меня. Я не знаю, почему, но когда я не передаю этот параметр, событие не захватывается. – melanholly

+0

@melanholly: Я думаю, что главный вопрос для этой темы, почему это не работает. Можете ли вы предоставить SSCCE? – lpapp