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

Manage Qthread -resource creation and deletion



  • Hi,

    i have an class "FelixThread" that inherited from QThread.
    inside

    void FelixThread::run()
    {
    process = new QProcess();
            process->setWorkingDirectory(workingDir);
    
            mutex.lock();
    
            process->start(solverPath, QIODevice::ReadWrite|QIODevice::Append);
            process->waitForStarted();
            if(process->state() != QProcess::ProcessState::Running) {
                mutex.unlock();
                return;
            }
    
            bool bLocked = true;
            while(1)
            {
                process->waitForReadyRead(-1);
                QString str = process->readAllStandardOutput();
                if(str.contains("Main Menu"))
                  break;
    
                if(str.contains("Opening Materials"))
                {
                    bLocked = false;
                    mutex.unlock();
                }
            }
    
            if(bLocked)
             mutex.unlock();
    
            process->write("3\n");
            process->waitForReadyRead(-1);
    
            for(int i = 0; i < fileIndex; i++)
    		{
    			QString name = QString("%1%2").arg(iterationName).arg(i+1);
    			if(numNodes <= 80000)
    			  name = iterationName;
    
    			process->write((name + ".felix\n").toAscii().data());
    		}
    	    
    		process->write("\n");
    
    		while(1)
            {
                process->waitForReadyRead(-1);
                QString str = process->readAllStandardOutput();
                if(str.contains("Main Menu"))
                  break;
            }
    
           process->write("5\n");
           process->waitForFinished(-1);
    
           delete process
    }
    

    Creation:

    FelixThread *thread = new FelixThread(dir.path(), ("\"" + QDir::currentPath() + "\\Felix_Strain.exe\""), iteration.name, fileIndex, numNodes, felixMutex);
    
    threads.append(thread);
    thread->start();
    

    i will create many thread based on value of felixThread->idealThreadCount() -2. Let's say if i have 20 loadcases to solve i will create 20 threads based on ideal thread count. if idealthreadcount is 5, the execution is divided to 4 batch in each batch 4 thread is created.

    The problem is, in one machine whose ideal thread count is 32, so all the 20 loadcases will be run on 20 different threads at same time. but after 10 loadcases or 13 loadcases ,it hangs after that. But few times it can able to solve all the loadcases.

    i Even tried to reduce the idealthreadcount to 8 and 10 but the result is same, it stops after 11 or 13 loadcases.

    In run(), am i allocating the resource to thread correctly or i need to change. Please help me


  • Banned

    This post is deleted!


  • You are using a thread just because you are obsessing over using syncronous operations of QProcess (i.e. waitFor methods). This should be all handled in the spawning (main?) thread connecting slots to the appropriate QProcess signals: https://doc.qt.io/qt-5/qprocess.html#signals



  • @heb8 Tried with QtConcurrent map method to create number of threads, but few times it doesn't create thread after solving like 18 loadcases and sometimes, it strucks at 15 loadcases


  • Qt Champions 2019

    @meganathan As @VRonin said: why do you use threads to use QProcess?! There is no need to do so.
    QProcess provides asynchronous API, use it instead of implementing work-arounds to use the synchronous one...



  • If i don't use QThread to solve the loadcases, at single point of time only one loadcase would be solved and makes execution time to take longer. Please suggest how can i use Qprocess with threads correctly or any other approach to solve


  • Qt Champions 2019

    @meganathan said in Manage Qthread -resource creation and deletion:

    at single point of time only one loadcase would be solved

    No it is not correct! As @jsulm already told you the QProcess stuff is async so you can start as much QProcess instances as you want in your main thread and you'll get a signal when each of them is finished.



  • Ok thanks,..i will try it out



  • i tried with asynchronous processes approach , but with that please help me with how to handle the write and wait appropriately.
    With the below approach i can able to run only one Qprocess, remaining gets struct.

    for(int i=0;i<8;i++)
    	{
    		stream << "started thread:" << i;
    		process = new QProcess();
    		process->setWorkingDirectory("C:\\Users\\H336803\\Documents\\Visual Studio 2005\\Projects\\QthreadTest\\QthreadTest\\output\\"+QString::number(i));
    		process->setObjectName("Loadcase"+QString::number(i));
    		connect(process,SIGNAL(started()),this,SLOT(processStarted()));
    		connect(process,SIGNAL(finished(int)),this,SLOT(processFinished(int)));
    		connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
    		connect(process,SIGNAL(error()),this,SLOT(processError()));
    		process->start("felix2.exe", QIODevice::ReadWrite|QIODevice::Append);
    
    }
    void QthreadTest::processStarted()
    {
    	QMutex mutex;
    	QString curr = process->objectName();
    	stream << ", Process name" << curr;
    
    	connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(readInput()));
    	}
    
    void QthreadTest::readInput()
    {
    		QString str = process->readAllStandardOutput();
    		if(str.contains("Main Menu"))
    		{
    			 process->write("3\n");
    			 connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(waitforWriting()));
    		}
    }
    void QthreadTest::waitforWriting()
    {
    	process->write("LoadCase1.felix\n");
    	process->write("\n");
    	
    	connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(readInput1()));
    
    }
    
    void QthreadTest::readInput1()
    {
    		QString str = process->readAllStandardOutput();
    		
    		if(str.contains("Main Menu"))
    		{
    			 process->write("5\n");
    			 connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(processFin()));
    		}
    }
    

  • Qt Champions 2019

    @meganathan said in Manage Qthread -resource creation and deletion:

    readyReadStandardOutput

    Why do you connect this signal to three different slots? All of them will be executed. You can handle everything with one slot, or disconnect slots you don't need anymore.



  • since can't use waitforReadReady() which blocks every qprocess


  • Lifetime Qt Champion

    Hi,

    An additional note, in your loop you are overwriting the same variable name process over and over again. This is not a good idea since you re-use it later on.



  • How can i use asynchronous Interactive QProcess withour waitforReadyRead(-1)? .Please help me how i can do it


  • Qt Champions 2019

    @meganathan said in Manage Qthread -resource creation and deletion:

    How can i use asynchronous Interactive QProcess withour waitforReadyRead(-1)?

    Using signals slots, but don't connect 3 different slots to same signal as I stated above.



  • You don't need to wait for writing, std i/o is buffered so if you don't care about the state you can write multiple things to the process at once and the process will receive them and use them in order without you needing anything else



  • i made the changes as requested, but am i facing problem to identify which process is started and which process has emitted readReadyStandardOutput().

    void QthreadTest::startThread()
    {
    processFinish =0;
    for(int i=0;i<8;i++)
    {
    stm << "started thread:" << i;
    process = new QProcess();
    listOfProcess->append(process);
    }
    startProcesses();
    }

    void QthreadTest::startProcesses()
    {
    for(int i=0;i<listOfProcess->size();i++)
    {
    listOfProcess[i]->setWorkingDirectory("C:\Users\H336803\Documents\Visual Studio 2005\Projects\QthreadTest\QthreadTest\output\"+QString::number(i));
    listOfProcess[i]->setObjectName("Loadcase"+QString::number(i));
    connect(listOfProcess[i],SIGNAL(started()),this,SLOT(processStarted()));
    connect(listOfProcess[i],SIGNAL(finished(int,QProcess::ExitStatus exitStatus)),this,SLOT(processFinished(int,QProcess::ExitStatus)));
    connect(listOfProcess[i],SIGNAL(readyReadStandardOutput()),this,SLOT(readInput()));
    connect(listOfProcess[i],SIGNAL(error()),this,SLOT(processError()));

    	listOfProcess[i]->start("felix2.exe", QIODevice::ReadWrite);
    }
    

    }

    void QthreadTest::readInput()
    {
    QString str = process->readAllStandardOutput(); // need help here

    	if(str.contains("Main Menu"))
    	{			
    		 process->write("3\n");			
    	}
    	else if(str.contains("Enter"))
    	{
    		process->write("LoadCase1.felix\n");
    		process->write("\n");
    	}
        else if(str.contains("Results"))
    	{
    		process->write("5\n");
    	}
    

    }

    As you can see in readInput() function , i coan't get which Qprocess is currently emitted readReadyStandardOuput() signal,
    Please help what i am doing wrong?


  • Qt Champions 2019

    @meganathan You can use new connect syntax and lambdas, like:

    connect(listOfProcess[i],&QPRocess::started, [listOfProcess[i], this] { ... });
    


  • @jsulm i am using Qt 4.8.5 ,this syntax won't work i guess


  • Qt Champions 2019

    @meganathan said in Manage Qthread -resource creation and deletion:

    this syntax won't work i guess

    True
    Then take a look at https://doc.qt.io/qt-5/qsignalmapper.html



  • Thanks this works


Log in to reply