Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Why the signal can't be sent to slot after an hour?



  • Hi everyone!
    I have recently happened a strange problem. I had connect a signal of class A to a slot function of class B. Then emit the signal later. At first, the slot function can work as I hope. The signal will be sent about 30 to 40 times per second. After about 260 thousand times, the slot stop to respond. I don't know the reason. Is there some one be kind to help me? Thx!

    Yours sinerely.


  • Lifetime Qt Champion

    Hi
    I would guess that whatever slot does, it might use some memory and you run out of it over time.
    Or something like that.
    Check memory usage for your app.



  • I think there should be some other reasons other than the frequency and the time it run. So I should told you about the structure of my application.
    I had a class which can read data from a serial port. In this class, a signal was declared. After data recived, it will save them and emit the signal.
    There is another class which will process the data. In this class, a slot function was declared. In the construction, a connect sentence is used to connect the signal and the slot. When the slot is executed, this class will access an interface of the class above(Serial port class). That class will copy the data it had recived and then delete it. By the way, all data is saved in a QQueue. The new data will append to the last. The first data will be copied and deleted.
    After more than an hour (aka. about 260 thousands access), the slot can't be execute after the signal emited. So the data will be accumlated, till the available memory is exhausted. Then the application is collapsed.



  • @Robert_is_not_robot
    I don't think anyone can possibly answer your question from your description, without code. I don't know what sort of answer you expect from what you have said.

    Produce a small example, profile the application, have a look at the memory consumption, put in debugging etc.



  • @JonB
    Your word is fair. There is a lot of code about this bug. It will take some time to post them. Please wait... Thank you.



  • At first, there is a class named HFDevice. It declare some function as below:

    class HFDevice
    {
    public:
            typedef struct{
                long len;
                unsigned char * pData;
            }HF_DATA_BULK, *PHF_DATA_BULK;
    ...
    public:
            //Unwrap the data from communication
            virtual void PrepareData() = 0;
    protected:
            //save communication data
            void SaveData(long len, unsigned char * pData);
    protected:
            QQueue<PHF_DATA_BULK> m_lsDataBulk;//Queue to save communication data
    ...
    };
    

    The function SaveData is implemented as below:

    void HFDevice::SaveData(long len, BYTE * pData)
    {
    	PHF_DATA_BULK pBulk = new HF_DATA_BULK();
    
    	pBulk->pData = new BYTE[len];
    	memcpy(pBulk->pData, pData, len);
    	pBulk->len = len;
    	m_lsDataBulk.enqueue(pBulk);
    }
    
    

    A class named CDeviceSerial which is derived from HFDevice. It declare the signal HadRecivedData and implement the function PrepareData:

    class CDeviceSerial: public QObject, public HFDevice
    {
            Q_OBJECT
    ...
    signals:
            //signal of recieved data
            void HadRecivedData(int devNumber);
    ...
    };
    
    void CDeviceSerial::PrepareData()
    {
            if (m_lsDataBulk.count() > 0)
            {
                m_Mutex.lock();
                PHF_DATA_BULK pBulk = m_lsDataBulk.takeFirst();
                m_Mutex.unlock();
                if (pBulk)
                {
                    //Unwrap the data and save them
                    ...
                    delete[] pBulk->pData;
                    delete pBulk;
                }
            }
    }
    

    In CDeviceSerial, a callback function is implemented to process the data read from serial port:

    BOOL CDeviceSerial:SerialDataArrived(unsigned char * pBuf, int len, void * pOwner)
    {
        CDeviceSerial * pThis = (CDeviceSerial *)pOwner;
        ...
        pThis->SaveData(len, pBuf);//Save the wrapped data
        emit pThis->HadRecivedData(pThis->m_pDevNumber);//emit signal
        ...
    }
    

    There is a class named HFMdiWindow to display the data. It is a QWidget. A button was clicked to start work. The slot function of that button is as below:

    void HFMdiWindow::OnClickOperate
    {
        HFDevice * pDev = NULL;
        ...
        for (int i = 0;i < m_lsDevNum.count();i ++)
        {
            pDev = (HFDevice *)m_pModel->GetModuleByNum(m_lsDevNum[i]);
            if (pDev->DoWork())
            {
                //Open serial port
                connect((CDeviceSerial *)pDev, SIGNAL(HadRecivedData(int)), this, SLOT(ProceedData(int)), Qt::QueuedConnection);//connect the signal and the slot
                ...
            }
            ...
        }
        ...
    }
    //Process the data
    void HFMdiWindow::ProceedData(int devNum)
    {
        if (m_lsDevNum.indexOf(devNum) == -1)
        {
            return;
        }
        HFDevice * pDevice = (HFDevice *)m_pModel->GetModuleByNum(devNum);
        if (pDevice == NULL)
            return;
        pDevice->PrepareData();//Unwrap the oldest data
        //below is the code to abstract the data one by one and display them
        ...
    }
    

    Almost all code was shown above. The unrelated code was omitted. I hope this will help you to solve my bug. Thx again!



  • Hi, just a guess but I don't see any matching disconnect() for the connect() statement in HFMdiWindow::OnClickOperate(), it might be you're running into some resource limit, perhaps the max. no of connect()s in Qt is 260 thousand...



  • @hskoglund
    I think disconnect() is not mandatory to match connect(), is it true?



  • You're right, normally disconnect() is not needed, but I was guessing that perhaps you did a new connect() 30 or 40 times per second, so that the pool of existing connections would overflow...



  • @hskoglund
    No, the connect() statement is in the function OnClickOperate(). And OnClickOperate() is a slot connected to the signal clicked() of QPushButton. So the connect() statement will only be executed when the button was clicked.


Log in to reply