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

QThread Signal not processed when ProgressDialog is Modal



  • Hi,
    I have some job to do, and i want split this job in 4 threads.
    Every thread must send a signal containing the progress in order to update a progress dialog.

    I've a simple Worker class :

    Worker::Worker(int _index)
    {
    	index = _index;
    }
    
    Worker::~Worker()
    {
    }
    
    void Worker::process() { 
    	qDebug() << "Job Start" << index;
    	for (long i = 0; i < 25; i++)
    	{
    		for (long j = 0; j < 2500000; j++)
    		{
    		      int t = sin(j) + cos(j) + tan(j) + j * cos(sin(j));
    		}
    		emit progress(index, 1);
    	}
    	qDebug() << "I ended my job" << index;
    	emit finished();
    	emit finish(index);
    }
    

    then, in the main window I call :

    QtThreadTest::QtThreadTest(QWidget *parent)
    	: QMainWindow(parent)
    {
    	ui.setupUi(this);
    	
    	checkCounter = 0;
    
    	for (int i = 0; i < 4; i++)
    	{
    		threadList.append(new QThread());
    		workerList.append(new Worker(i));
    	}
    
    	for (int i = 0; i < 4; i++)
    	{
    		QThread *thread = threadList.at(i);
    		Worker  *worker = workerList.at(i);
    		worker->moveToThread(thread);
    		QObject::connect(worker, SIGNAL(progress(int, int)), this, SLOT(updateProgressDialog(int, int)));
    		QObject::connect(thread, SIGNAL(started()),  worker, SLOT(process()));
    		QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
    		QObject::connect(worker, SIGNAL(finish(int)), this, SLOT(manageFinish(int)));
    		QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    		checkCounter++;
    	}
    	progressDialog.setModal(true);
    	progressDialog.show();
    
    	for (int i = 0; i < 4; i++)
    	{
    		QThread *thread = threadList.at(i);
    		thread->start();
    	}
    
    }
    
    void QtThreadTest::updateProgressDialog(int index, int val)
    {
    	qDebug() << "Received Progress" << val << "from Thread" << index;
    	mutex2.lock();
    	int old = progressDialog.value();
    	progressDialog.setValue(old+val);
    	mutex2.unlock();
    }
    
    void QtThreadTest::manageFinish(int index)
    {
    	mutex.lock();
    	checkCounter--;
    	if (checkCounter == 0)
    	{
    		qDebug() << "ALL FINISHED" << index;
    		progressDialog.close();
    	}
    	mutex.unlock();
    }
    

    Everytime I run this program I always get an "incomplete" progress dialog (sometimes shows 5%, sometimes 7%, sometimes 10%)
    this is the output :

    Job Start 0
    Job Start 1
    Job Start 3
    Job Start 2
    Received Progress 1 from Thread 3
    Received Progress 1 from Thread 1
    Received Progress 1 from Thread 2
    Received Progress 1 from Thread 0
    Received Progress 1 from Thread 1
    Received Progress 1 from Thread 3
    Received Progress 1 from Thread 2
    Received Progress 1 from Thread 0
    Received Progress 1 from Thread 1
    Received Progress 1 from Thread 3
    Received Progress 1 from Thread 0
    Received Progress 1 from Thread 2
    I ended my job 0
    I ended my job 1
    I ended my job 2
    I ended my job 3
    

    The mainwindows misses a lot of signals emitted from the threads:

    • a lot of progress(int,int) singlas
    • 4x finished() signals
    • 4x finish(int) signals
      why ?

    If I set the progress dialog not modal -> progressDialog.setModal(false) I have the correct behavior :

    Job Start 0
    Job Start 1
    Job Start 3
    Job Start 2
    Received Progress 1 from Thread 1
    Received Progress 1 from Thread 3
    Received Progress 1 from Thread 2
    ...
    ... 
    ...
    ...
    Received Progress 1 from Thread 0
    I ended my job 1
    Received Progress 1 from Thread 1
    Il thread 0x1f60 è terminato con il codice 0 (0x0).
    I ended my job 3
    Received Progress 1 from Thread 3
    Il thread 0x3f74 è terminato con il codice 0 (0x0).
    I ended my job 2
    Received Progress 1 from Thread 2
    Il thread 0x2154 è terminato con il codice 0 (0x0).
    I ended my job 0
    Received Progress 1 from Thread 0
    ALL FINISHED 0
    Il thread 0x13cc è terminato con il codice 0 (0x0).
    

    What is the mistake?
    A bad thread managing ?
    A bad signals/slots managing ?
    both ?

    Thank you,
    Salvo



  • @parisisal said in QThread Signal not processed when ProgressDialog is Modal:

    progressDialog.setModal(true);
    progressDialog.show();

    for (int i = 0; i < 4; i++)
    {
    QThread *thread = threadList.at(i);
    thread->start();
    }

    Since .show() will only return after the user closes the dialog in case it is set as modal. Your threads will be started afterwards. I'll suggest to change your code order:

        for (int i = 0; i < 4; i++)
        {
           QThread *thread = threadList.at(i);
            thread->start();
        }
        progressDialog.setModal(true);
        progressDialog.show();
    

    Furthermore I'd like to suggest to take a look at the QThreadPool class. It will perfectly suits your needs in this case.



  • Thank you, I'll try.
    I have a question.
    If .show() is blocking (returns after the user closes the dialog), why the Threads starts ?
    In the output I see :

    Job Start 0
    Job Start 1
    Job Start 3
    Job Start 2
    Received Progress 1 from Thread 3
    Received Progress 1 from Thread 1
    Received Progress 1 from Thread 2
    Received Progress 1 from Thread 0
    Received Progress 1 from Thread 1
    Received Progress 1 from Thread 3
    Received Progress 1 from Thread 2
    Received Progress 1 from Thread 0
    Received Progress 1 from Thread 1
    Received Progress 1 from Thread 3
    Received Progress 1 from Thread 0
    Received Progress 1 from Thread 2
    I ended my job 0
    I ended my job 1
    I ended my job 2
    I ended my job 3
    

    The job starts, do the work, and ends. But the signals/slots doesn't work.


  • Moderators

    hi @parisisal

    I think the issue is with progressDialog, you should set the maximum, (the default is 100 but just in case) and you should set the minimum, as that resets the current value to 0.

    that said, from the docu it says:

    Warning: If the progress dialog is modal (see QProgressDialog::QProgressDialog()), setValue() calls QApplication::processEvents(), so take care that this does not cause undesirable re-entrancy in your code. For example, don't use a QProgressDialog inside a paintEvent()!
    

    that means, when one signal is invoking the slot, all queued signals will be processed, and because the set value function is mutex locked, they will exit the slot without modifiying the value.


    you could try setting a member int and increase that, and print it to the console, to see if it reaches 100 or not


Log in to reply