Solved Slot priority in multithread
-
Hi all!
Small fragment of the project:
mainwindow.cpp
//constructor QThread *thread = new QThread; //thread = new QThread(this); valve = new Valve(7); pressureSensors = new PressureSensors; valve->moveToThread(thread); pressureSensors->moveToThread(thread); connect(pressureSensors, SIGNAL(remoteSignal(bool)), this, SLOT(readPressureSensors(bool))); connect(valve, SIGNAL(remoteSignal(bool)), this, SLOT(updateStates(bool))); connect(this, SIGNAL(valveOpen(int)), valve, SLOT(open(int))); connect(this, SIGNAL(valveClose(int)), valve, SLOT(close(int))); connect(valve, SIGNAL(valveStatus(int,bool,bool)), this, SLOT(valveIndicate(int,bool,bool))); QTimer *sensorsReadTimer = new QTimer(this); sensorsReadTimer->moveToThread(thread); connect(sensorsReadTimer, SIGNAL(timeout()), pressureSensors, SLOT(readSensors())); sensorsReadTimer->start(100); QTimer *valvesReadTimer = new QTimer(this); valvesReadTimer->moveToThread(thread); connect(valvesReadTimer, SIGNAL(timeout()), valve, SLOT(getAllStates())); valvesReadTimer->start(100); thread->start(); //***// void MainWindow::openValve(int id) { valveButton[id]->setEnabled(false); //valve->open(id); emit valveOpen(id); }
protocol.cpp
bool Valve::open(int id) { QByteArray arr; arr.resize(7); arr[0] = 0xAB; arr[1] = 0x01; arr[2] = 0x02; arr[3] = 0x02; arr[4] = id + 1; arr[5] = 0xFF; arr[6] = 0x00 - arr[1] - arr[2] - arr[3] - arr[4] - arr[5]; QByteArray response = ComPort::get().requestResponse(arr); if(response[0] == arr[0]) { qDebug() << "клапан №: " << id << " открыт!"; valveState[id] = true; emit valveStatus(id, 1, 1); return 1; } emit valveStatus(id, 1, 0); return 0; } bool Valve::getAllStates() { QByteArray arr; arr.resize(5); arr[0] = 0xAB; arr[1] = 0x01; arr[2] = 0x00; arr[3] = 0x00; arr[4] = 0x00 - arr[1] - arr[2] - arr[3]; QByteArray response = ComPort::get().requestResponse(arr); if(response[0] == arr[0]) { QBitArray bitStates(16); for (int i = 4; i<6; i++) for (int b = 0; b<8; b++) bitStates.setBit((i-4)*8+b, response.at(i)&(1<<b)); for (int i = 0; i < valveState.size(); i++) valveState[i] = bitStates[i]; for (uint i = 0; i < sizeof(fittingState); i++) fittingState[i] = bitStates[i+8]; emit remoteSignal(1); return 1; } emit remoteSignal(0); return 0; } //***// QByteArray ComPort::requestResponse(const QByteArray &data) { mutex->lock(); QByteArray readBuf; qDebug() << "-------------------------"; if(!serial->isOpen()) open(); int attempts = 1; while (attempts <= REQATTEMPTS) { //3 попытки if (serial->isWritable()) { serial->write(data); qDebug() << "Попытка № " << attempts; qDebug() << "Запрос: " << data.toHex(); while (serial->waitForReadyRead(WAITFORREADY)) { readBuf += serial->readAll(); if (crcCheck(readBuf) && data[2] == readBuf[2] ){ //если CRC и команда сошлись -- успех! qDebug() << "Ответ: " << readBuf.toHex(); responseCount++; qDebug() << "Кол-во запросов: " << responseCount; qDebug() << "Кол-во таймаутов: " << timeoutCount; float percent = timeoutCount * 100; percent = percent / responseCount; qDebug() << "Процент косяков: " << QString::number(percent, 'f', 3) << "%"; close(); mutex->unlock(); return readBuf; } } //qDebug() << readBuf.toHex(); readBuf.clear(); qDebug() << "Таймаут..."; timeoutCount++; close(); open(); attempts++; } else { qDebug() << "Порт " << portName << " не пишется!"; close(); mutex->unlock(); return 0; } } close(); mutex->unlock(); return 0; }
If I do not put valve and pressureSensors in a separate thread, then everything works more or less normally.
But if I put them in a separate thread, the valve opening slot works very late (~ 10-20 seconds, as lucky). As I understand it, this is because the signal is emitted from the main thread, and the slot is in the other thread. Is it possible to build a queue?Slot open from Valve class must have the highest priority
Thankful in advance for the help!
-
Since you've given a parent to the timers they wouldn't be able to move them to another thread.
My suspect is that it's not a problem of the connection itself but of your blocking design of the serial read. Try connecting a slot or lambda to readyRead instead of using waitForReadyRead
-
@VRonin
Timers have nothing to do with it. I tried it differently. The poll of the valves unambiguously moves to a separate thread, as the graphical interface stops lagging.
I need to wait a certain amount of time to get a response on the port, otherwise continue the poll. The valve opening slot for some reason starts very late (check with qDebug()) -
@maratk1n said in Slot priority in multithread:
I need to wait
Yes, my point is that you do not, you can use it asynchronously
@maratk1n said in Slot priority in multithread:
The valve opening slot for some reason starts very late
This is probably because the event loop in the receiver is busy
@maratk1n said in Slot priority in multithread:
Timers have nothing to do with it.
Agree, nevertheless they are not moved to the separate thread
-
Changed some code. This, it seems, helped to solve the problem.
... QTimer *sensorsReadTimer = new QTimer(this); // <<<<<<<<<< Change to new QTimer(); sensorsReadTimer->moveToThread(thread); connect(sensorsReadTimer, SIGNAL(timeout()), pressureSensors, SLOT(readSensors())); sensorsReadTimer->start(100); // <<<<<<<<<< Start the timer before moving to the thread QTimer *valvesReadTimer = new QTimer(this); // <<<<<<<<<< Change to new QTimer(); valvesReadTimer->moveToThread(thread); connect(valvesReadTimer, SIGNAL(timeout()), valve, SLOT(getAllStates())); valvesReadTimer->start(100); // <<<<<<<<<< Start the timer before moving to the thread ...
@VRonin Thanks :)