PDA

View Full Version : Slot priority in multithread



maratk1n
11th May 2017, 17:42
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 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!

Santosh Reddy
12th May 2017, 12:07
There are 2 problems in the code
1. QTimers are created with a parent. Objects with a parent cannot be moved to a thread
Fix: Create QTimer without parent

2. QTimer is started after moving to thread. You cannot and should not start a timer which is in another thread.
Fix: Start the timer before moving to the thread.



...
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
...

maratk1n
12th May 2017, 13:04
There are 2 problems in the code
1. QTimers are created with a parent. Objects with a parent cannot be moved to a thread
Fix: Create QTimer without parent

2. QTimer is started after moving to thread. You cannot and should not start a timer which is in another thread.
Fix: Start the timer before moving to the thread.



Thank you very much!:) This, it seems, helped to solve the problem.