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 :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.