I have a case where a signal is being lost and I don't understand why -- normally signals sent prior to the event loop starting just get queued up and sent then.
This is what the code looks like (for a QThread object):
void OffloadHandler::run()
{
cout << "Start" << endl;
connect( this, SIGNAL(loopStarted()), SLOT(onLoopStarted()), Qt::QueuedConnection );
emit loopStarted();
exec();
}
void OffloadHandler::onLoopStarted()
{
cout << "Here!" << endl;
}
The thread is started elsewhere and Start is written to the console but Here1 never is -- the signal is not received. I use the same pattern in my main message loop and it works, but in this threaded message loop it appears not to work.
Is there anything clearly wrong in my code here?
Your code is valid and it should run. Are you sure you have an event loop running in the thread that oh is created in?
Cause the emit loopStarted() should send an event to oh's event loop, which will be processed and will call onLoopStarted(). I've tested your code out, and it works for me.
Btw, It's generally recommended that you do not add slots to your QThread, and avoid using moveToThread( this );
Unfortunately, I don't really understand your use case, so I can't give a better solution. But here is some amazing documentation which has nice DOs and DONTs regarding QThreads.
Okay, I've figured it out, I've been bitten by the QThread ownership oddity. One has to be really careful when connecting to the QThread object itself since that Object is not owned by the thread by default.
So at the point where the thread is created I must move the thread to the thread:
OffloadHandler * oh = new OffloadHandler();
oh->moveToThread( oh ); //MOVE TO SELF!
oh->start();
Once I do this the signals work as expected.
Related
I am currently working on an editor program; there's a feature I need to write, which requires loading several files in a row using the project's asynchronous file API, then performing some more computations once those files are loaded.
In another language, this would probably be implemented with an async/await workflow, eg:
let firstFile = await FileAPI.loadFile("Foo.xxx", ...);
let otherFile = await FileAPI.loadFile("Bar/Foobar.xxx", ...);
The Qt equivalent to this code would be to spawn a new thread using QtConcurrent::run, returning a QFuture, and waiting for that future to yield a result.
However, in the project I work on, the file-opening API runs on a single worker thread, which means I can't use QtConcurrent::run. This is an established, non-negotiable part of the codebase. Eg the constructor of the file API looks like:
FileApiWorker* worker = new FileApiWorker();
m_workerThread = new QThread();
worker->moveToThread( m_workerThread );
// Input signals
connect( this, &FileApi::loadFile, worker, &FileApiWorker::loadFile);
connect( this, &FileApi::loadData, worker, &FileApiWorker::loadData);
connect( this, &FileApi::loadDir, worker, &FileApiWorker::loadDir);
Which means my only way of accessing filesystem data is to call a method which emits a signal, which starts the computation on another thread, which eventually emits its own signal at the end to pass on the loaded data.
This is extremely impractical for the use case above, because instead of saying "do thing, load data, wait, keep doing things", I essentially need to say "do thing, load data (with call back 'keep doing things')" and "keep doing things" in another function, which introduces all sorts of brittleness in the code. (and, well, you know, that's exactly the sort of workflow we invented futures for)
Is there some way I could create a QFuture, or some future-equivalent object (that can be awaited inside a method) from the loadFile method, given that loadFile always runs on the same worker thread and I am not allowed to create new threads?
The simplest way to create a QFuture in Qt is with the undocumented QFutureInterface class.
Example code:
Q_DECLARE_METATYPE( QFutureInterface<FileData> );
// ...
qRegisterMetaType<QFutureInterface<FileData>>();
FileApiWorker* worker = new FileApiWorker();
connect( this, &FileApi::loadFile_signal, worker, &FileApiWorker::loadFile_signal);
// ...
QFuture<FileData> FileApi::loadFile()
{
QFutureInterface<FileData> futureInterface;
// IMPORTANT: This line is necessary to be able to wait for the future.
futureInterface.reportStarted();
emit loadFile_signal(futureInterface);
return futureInterface.future();
}
FileApiWorker::loadFile_signal(QFutureInterface<FileData>& futureInterface)
{
// Do some things
// ...
futureInterface.reportResult(...);
// IMPORTANT: Without this line, future.waitForFinished() never returns.
futureInterface.reportFinished();
}
Some factors to account for:
The above code uses Q_DECLARE_METATYPE; which is necessary to be able to pass QFutureInterface through a cross-threads signal. To be precise, the connect line will fail to compile if Q_DECLARE_METATYPE isn't included; and the emit loadFile_signal line will fail at runtime if qRegisterMetaType isn't called. See the Qt documentation on metatypes for details.
You can propagate errors, in such a way that calling loadFile().waitForFinished() throws on error. To achieve this, you need to create a special-purpose class inheriting QException, then call:
futureInterface.reportException( MyException(...) );
futureInterface.reportFinished();
in your error path.
QException is essentially a wrapper for actual exceptions that need to be transferred between threads. See the documentation for details.
While QFutureInterface is stable, and mostly has the same API as QFuture and QFutureWatcher, it's still an undocumented feature, which may surprise contributors coming across it in a shared codebase. The class can be counter-intuitive, and fail silently if you don't respect the points above (which I had to learn through trial and error). This must be stressed in the comments of any shared code using QFutureInterface. The class's source code can be found here.
IMO, it is strange not to use ready-to-use solutions (AsyncFuture) and try to rewrite from scratch.
But I can suggest my own "wheel": lambda as a slot.
void FileApi::awaitLoadFile()
{
qDebug() << "\"await\" thread is" << thread();
emit loadFile("Foo.xxx");
static bool once = connect(m_worker, &FileApiWorker::loadFileDone, this, // there is possible to avoid the third "this" parameter, but it is important to specify the lifetime of the connection and the receiver context while using lambdas
[=](QByteArray result)
{
qDebug() << "\"comeback-in-place\" thread is" << thread(); // will be the same as "await" thread was
// do what you need with your result
},
Qt::QueuedConnection // do not forget
);
qDebug() << "here is an immediate return from the \"await\" slot";
}
Useful arcticle New Signal Slot Syntax - Qt Wiki
I have this code:
mainwindow.h:
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
private:
QMutex mutex;
}
mainwindow.cpp:
void MainWindow::on_calculateBtn_clicked() {
QMutexLocker locker(&mutex);
qDebug() << "mutex has been locked" << endl;
ui->calculateBtn->setEnabled(false);
startProcess(); // huge calcutations
ui->calculateBtn->setEnabled(true); // performed before startProcess() has finished (why?)
qDebug() << "mutex will be unlocked" << endl;
}
If I click calculateBtn again while startProcess() has not finished, my program crashed:
pure virtual method called
The program has unexpectedly finished.
I tried:
void MainWindow::on_calculateBtn_clicked() {
if (!processing) {
processing = true;
ui->calculateBtn->setEnabled(false);
startProcess();
ui->calculateBtn->setEnabled(true); // performed before startProcess() has finished (why?)
processing = false;
}
}
There is no shared data, I just want one startProcess() will not be started before other startProcess() finished.
Why did it happen? I think that mutex have to lock function startProcess() in on_calculateBtn_clicked() and nothing should happens. It seems I don't know any important things. Thanks in advance for any advice.
The same mutex is locked twice from the same thread (the main thread, which contains the event loop), which is invalid for a non-recursive mutex.
But even a recursive mutex will not solve the basic problem of your code; you need a flag to indicate that you are already doing the calculations, and return from all subsequent calls to your method while they are running, else you'll start them multiple times in the same thread, one interrupting the other, probably with bad results. Even better, disable the button while the method is running and take care it isn't called by other ways.
However, if calling startProcess() multiple times and run it simultaneously is intended, you'll have to start a thread for each button press and take care for access to shared data (using mutexes, most probably) - that's where the real fun begins.
I think that you (by default) have a Qt::DirectConnection with this button press, right? i.e.:
connect(..., SIGNAL(...),
..., SLOT(:on_calculateBtn_clicked()), <by-default-Qt::DirectConnection>);
The issue I see here is that the first button press will run the function void MainWindow::on_calculateBtn_clicked() immediately.... which is all good so far, the mutex is locked and huge calcs are running.
However when you press the button again, void MainWindow::on_calculateBtn_clicked() is again immediate run (like an interrupt). The first thing it does is try to lock the mutex and it must hang here.
If you make connection to the slot void MainWindow::on_calculateBtn_clicked() Qt::QueuedConnection then it won't trigger the button press until it has clear the other tasks on its task queue.
but.... weather or not your design here is good is questionable, I think over you should re-think your strategy (as some comments have suggested)
EDIT
Oh yeah, meant to add..... to answer your question, therefore I don't think the mutex is begin unlocked twice... its just the nature of the direct connection
I'm using QtConcurrent to do some heavy background image processing and I want to display the image while parts of it are being updated progressively.
Each line of the image is computed separately and is passed a functor.
To compute the full image I then have a sequence of item that I pass to QtConcurrent mapped and each line emits a signal when it is done computing
Here is the instantiation of the class Worker:
//living in the main(gui) thread !
Worker::Worker(VideoEngine* engine):_engine(engine){
_watcher = new QFutureWatcher<bool>;
_watcher->setPendingResultsLimit(200);
connect(_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
Here is the slot to report progress:
void Worker::onProgressUpdate(int i){
if(i < (int)_rows.size() && i%10==0){
cout << " index = " << i << " y = "<< _rows[i] << endl;
_engine->checkAndDisplayProgress(_rows[i],i);
}
}
Now the usage:
void Worker::_computeTreeForFrame(.../*unrelevant args*/){
....
....
_watcher->setFuture(
QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
}
}
All the signals are emitted but the slot onProgressUpdate gets called only when Qtconcurrent::mapped is done with all the items in the sequence.
When executing it has a huge delay while the sequence is processing and then all slots are executed sequentially afterwards.
I have tried all types of signal/slots connection and none of them changed this behaviour.
Any clue ?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after Shf suggestion
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The call was made until now in the main(gui) thread.
I changed the call to :
_computeFrameWatcher->setFuture(QtConcurrent::run(_worker,&Worker::computeTreeForFrame));
Since _computeTreeForFrame is now executed in another thread, I changed the call to QtConcurrent::mapped to:
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
This results in exactly the same behaviour as before.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after Marek R suggestion
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ok so I made so tests and here is what I observed:
QtConcurrent::map :
Doesn't emit the signal resultReadyAt(int)
QtConcurrent::mapped
Emits resultReadyAt(int) only when finished
It doesn't matter if the call to the map function is done in a separate thread the same behaviour is encountered.
I also gave a try to the signal progressValueChanged(int) as the Qt progressDialog example suggests.
The signal progressValueChanged(int) gets emitted only for 2 lines in the image (the first and last).
This is really weird as in the Qt progress dialog example it is emitted smoothly.
I changed a bit the Qt example to launch the map function in another thread than the main thread and it still works well in that case.
The issue must arise from somewhere else.
Maybe the GUI event loop is doing something I don't expect ? I have no clue what.
I will now try QtConcurrent::mappedReduced and report with the results :-)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after giving a try to QtConcurrent::mappedReduced
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
It doesn't work and calls the "reduce" function ONLY when the "map" function is done. In other words it does the same than the previous signal/slots mechanism.
I'm running low in possibilities now
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT I'm back to a solution as close as the Qt progress dialog example
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Something must be wrong if I can't get the same behaviour than the Qt example.
Here's the code now:
//created in the main thread! (gui)
Worker::Worker(VideoEngine* engine):_engine(engine),_watcher(0){
_watcher = new QFutureWatcher<void>;
_watcher->setPendingResultsLimit(200);
connect(_watcher,SIGNAL(progressValueChanged(int)), _engine,
SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
//executed on the main thread
void Worker::computeTreeForFrame(...){
...
_watcher->setFuture(QtConcurrent::map(_sequence,boost::bind(metaEnginePerRow,_1,output)));
...
}
The call to computeTreeForFrame...
...
_worker->computeTreeForFrame();
...
This call is done in a slot .
It emits the signals for the line 0 and for the last line as told before but doesn't emits anything else.
Shouldn't this do EXACTLY what the Qt example does?
From task description it looks like you should use mappedReduced. Problem is that I don't see a good way to get partial results. One way to overcome this problem is to emit signal form reduce function.
It is possible that this thread may help.
It seems, that QtConcurrent::mapped does not put VideoEngine::metaEnginePerRow in another thread, judging by the documentation. If image is processed in the same thread as GUI, then your slots indeed will be executed after processing, no matter what type of connection you select, just as you've described.
The solution is to either run Worker::_computeTreeForFrame (as i understood, your main processing function) in another thread via QtConcurrent::run or to put your Worker object in another thread probably via QObject::moveToThread(). Then, the connection type you should use is Qt::QueuedConnection (or if you will put Worker in another thread before connection, you can connect even with Qt::AutoConnectionor Qt::UniqueConnection, caller and receiver will be in a different threads, so qt will automaticly chose QueuedConnection`)
EDIT:
I'm not sure, but your _watcher = new QFutureWatcher<bool>; is still created in the main thread and if you call
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
would _watcher set GUI thread to wait, in what it was created or thread, where this command is executed. If _watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output))); if the end of a function, is _watcher->waitForFinished(); needed at all? Qt will destroy thread right after it's execution and you set your processing function to run, why wait?
And _computeFrameWatcher should be of QFuture<void*> type.
EDIT2:
Ok, before i give up, i suggest you to test QObject::moveToThread:
before you call _worker->computeTreeForFrame(); , put it in another thread:
QThread *workerThread=new QThread();
_worker->moveToThread();
_worker->computeTreeForFrame();
/* connect _worker's finished signal with workerThread::quit and deleteLater slots */
and all connections within _worker should be DirectConnection and all connections between _worker and main (GUI) thread should be connected with QueuedConnection. Also it's probably good to create new thread in _worker constructor and move it to another thread immediately, this way you can destroy thread in _worker's destructor and don't worry about thread problem's in GUI thread
When using QTcpSocket to receive data, the signal to use is readyRead(), which signals that new data is available.
However, when you are in the corresponding slot implementation to read the data, no additional readyRead() will be emitted.
This may make sense, as you are already in the function, where you are reading all the data that is available.
Problem description
However assume the following implementation of this slot:
void readSocketData()
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
}
What if some data arrives after calling readAll() but before leaving the slot?
What if this was the last data packet sent by the other application (or at least the last one for some time)?
No additional signal will be emitted, so you have to make sure to read all the data yourself.
One way to minimize the problem (but not avoid it totally)
Of course we can modify the slot like this:
void readSocketData()
{
while(socket->bytesAvailable())
datacounter += socket->readAll().length();
qDebug() << datacounter;
}
However, we haven't solved the problem. It is still possible that data arrives just after the socket->bytesAvailable()-check (and even placing the/another check at the absolute end of the function doesn't solve this).
Making sure to be able to reproduce the problem
As this problem of course happens very rarely, I stick to the first implementation of the slot, and I'll even add a an artificial timeout, to be sure that the problem occurs:
void readSocketData()
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
// wait, to make sure that some data arrived
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
}
I then let another application send 100,000 bytes of data.
This is what happens:
new connection!
32768 (or 16K or 48K)
The first part of the message is read, but the end isn't read anymore, as readyRead() won't be called again.
My question is: what is the best way to be sure, this problem never occurs?
Possible solution
One solution I came up with is calling the same slot again at the end again, and to check at the beginning of the slot, if there is any more data to read:
void readSocketData(bool selfCall) // default parameter selfCall=false in .h
{
if (selfCall && !socket->bytesAvailable())
return;
datacounter += socket->readAll().length();
qDebug() << datacounter;
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
QTimer::singleShot(0, this, SLOT(readSocketDataSelfCall()));
}
void readSocketDataSelfCall()
{
readSocketData(true);
}
As I don't call the slot directly, but use QTimer::singleShot(), I assume that the QTcpSocket can't know that I'm calling the slot again, so the problem that readyRead() isn't emitted can't happen anymore.
The reason why I have included the parameter bool selfCall is that the slot which is called by the QTcpSocket isn't allowed to exit sooner, else the same problem can occur again, that data arrives exactly at the wrong moment and readyRead() isn't emitted.
Is this really the best solution to solve my problem?
Is the existence of this problem a design error in Qt or am I missing something?
Short answer
The documentation of QIODevice::readyRead() states:
readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted.
Thus, make sure that you
don't instantiate a QEventLoop inside your slot,
don't call QApplication::processEvents() inside your slot,
don't call QIODevice::waitForReadyRead() inside your slot,
don't use the same QTcpSocket instance within different threads.
Now you should always receive all data sent by the other side.
Background
The readyRead() signal is emitted by QAbstractSocketPrivate::emitReadyRead() as follows:
// Only emit readyRead() when not recursing.
if (!emittedReadyRead && channel == currentReadChannel) {
QScopedValueRollback<bool> r(emittedReadyRead);
emittedReadyRead = true;
emit q->readyRead();
}
The emittedReadyRead variable is rolled back to false as soon as the if block goes out of scope (done by the QScopedValueRollback). So the only chance to miss a readyRead() signal is when the control flow reaches the if condition again before the processing of the last readyRead() signal has finished (in other words, when there would be a recursion).
And a recursion should only be possible in the situations listed above.
I think scenario mentioned in this topic has two major cases which works differently, but in general QT doesn't have this problem at all and I will try to explain below why.
First case: Single threaded application.
Qt uses select() system call to poll open file descriptor for any change happened or operations available. Simple saying on every loop Qt checks if any of opened file descriptors have data available to read/closed etc. So on single threaded application flow looks like that (code part simplified)
int mainLoop(...) {
select(...);
foreach( descriptor which has new data available ) {
find appropriate handler
emit readyRead;
}
}
void slotReadyRead() {
some code;
}
So what will happend if new data arrived while program still inside slotReadyRead.. honestly nothing special. OS will buffer data, and as soon as control will return to next execute of select() OS will notify software that there are data available for particular file handle. It works in absolutely the same way for TCP sockets/files etc.
I can imaging situations where (in case of really long delays in slotReadyRead and a lot of data coming) you can experience an overrun within OS FIFO buffers (for example for serial ports) but that has more to do with a bad software design rather then QT or OS problems.
You should look on slots like readyRead like on a interrupt handlers and keep their logic only within fetch functionality which fills your internals buffers while processing should be done in separate threads or while application on idle etc.. Reason is that any such application in general is a mass service system and if it spends more time on serving one request then a time interval between two requests it's queue will overrun anyway.
Second scenario: multithreaded application
Actually this scenario is not that much differ from 1) expect that you should design right what happens in each of your threads. If you keep main loop with light wighted 'pseudo interrupt handlers' you will be absolutely fine and keep processing logic in other threads, but this logic should work with your own prefetch buffers rather then with QIODevice.
The problem is quite interesting.
In my program the usage of QTcpSocket is very intensive. So I've written the whole library, that breaks outgoing data into packages with a header, data identifier, package index number and maximum size, and when the next piece of data comes, I know exactly where it belongs to. Even if I miss something, when the next readyRead comes, the receiver reads all and compose received data correctly. If the communication between your programs is not so intense, you could do the same, but with timer (which is not very fast, but solves the problem.)
About your solution. I don't think it's better then this:
void readSocketData()
{
while(socket->bytesAvailable())
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
}
}
The problem of both methods is the code right after leaving the slot, but before returning from emitting the signal.
Also you could connect with Qt::QueuedConnection.
Here are some examples of ways to get the whole file, but using some other parts of the QNetwork API:
http://qt-project.org/doc/qt-4.8/network-downloadmanager.html
http://qt-project.org/doc/qt-4.8/network-download.html
These examples show a stronger way to handle the TCP data, and when buffers are full, and better error handling with a higher level api.
If you still want to use the lower level api, here is a post with a great way to handle the buffers:
Inside your readSocketData() do something like this:
if (bytesAvailable() < 256)
return;
QByteArray data = read(256);
http://www.qtcentre.org/threads/11494-QTcpSocket-readyRead-and-buffer-size
EDIT: Additional examples of how to interact with QTCPSockets:
http://qt-project.org/doc/qt-4.8/network-fortuneserver.html
http://qt-project.org/doc/qt-4.8/network-fortuneclient.html
http://qt-project.org/doc/qt-4.8/network-blockingfortuneclient.html
Hope that helps.
If a QProgressDialog shall be shown while receiving data from a socket it only works if any QApplication::processEvents() are sent (e.g. by the QProgessDialog::setValue(int) methode). This of course leads to the loss of readyRead signals as mentioned above.
So my workaround was a while loop including the processEvents command such as:
void slot_readSocketData() {
while (m_pSocket->bytesAvailable()) {
m_sReceived.append(m_pSocket->readAll());
m_pProgessDialog->setValue(++m_iCnt);
}//while
}//slot_readSocketData
If the slot is called once any additional readyRead signals can be ignored because the bytesAvailable() always returns the actual number after the processEvents call. Only on pausing of the stream the while loop ends. But then the next readReady is not missed and starts it again.
I had the same problem right away with the readyRead slot. I disagree with the accepted answer; it doesn't solve the problem. Using bytesAvailable as Amartel described was the only reliable solution I found. Qt::QueuedConnection had no effect. In the following example, I'm deserializing a custom type, so it's easy to predict a minimum byte size. It never misses data.
void MyFunExample::readyRead()
{
bool done = false;
while (!done)
{
in_.startTransaction();
DataLinkListStruct st;
in_ >> st;
if (!in_.commitTransaction())
qDebug() << "Failed to commit transaction.";
switch (st.type)
{
case DataLinkXmitType::Matrix:
for ( int i=0;i<st.numLists;++i)
{
for ( auto it=st.data[i].begin();it!=st.data[i].end();++it )
{
qDebug() << (*it).toString();
}
}
break;
case DataLinkXmitType::SingleValue:
qDebug() << st.value.toString();
break;
case DataLinkXmitType::Map:
for (auto it=st.mapData.begin();it!=st.mapData.end();++it)
{
qDebug() << it.key() << " == " << it.value().toString();
}
break;
}
if ( client_->QIODevice::bytesAvailable() < sizeof(DataLinkListStruct) )
done = true;
}
}
i got the same problem, rather use signal readyRead() and socket.readall, i' m trying the following, just after connect without be sure :
QByteArray RBuff;
if(m_socket->waitForConnected(3000))
{
while (m_socket->ConnectedState == QAbstractSocket::ConnectedState) {
RBuff = m_socket->read(2048);
SocketRead.append(RBuff);
if (!SocketRead.isEmpty() && SocketRead.length() == 2048)
{
readData(SocketRead);
SocketRead.remove(0,2048);
}
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
//m_socket->close();*/
}
else
{
I have been learning Qt for a while and a few days ago I decided to go on multi-threading by QThread. I have been following this person. Since he says that subclassing QThread is not the appropriate way but by using QObject is. I am following his method. But he has created another class which inherits from QObject. I decided to make a few changes:
class myclass
{
private:
dowork();
private slots:
slota();
slotb();
slotc();
}
myclass::dowork()
{
QThread lett;
QThread latt;
QThread pltt;
QObject lethread;
connect(&lett, SIGNAL(started()), this, SLOT(slota()));
lethread.moveToThread(&lett);
QObject lathread;
connect(&latt, SIGNAL(started()), this, SLOT(slotb()));
lathread.moveToThread(&latt);
QObject plthread;
connect(&pltt, SIGNAL(started()), this, SLOT(slotc()));
plthread.moveToThread(&pltt);
lett.start();
latt.start();
pltt.start();/*
lett.wait();
latt.wait();
pltt.wait();*/
while(lett.isRunning())
{
//qDebug() << "Still Running!";
}
lett.quit();
}
If I run the program it keeps running while loop infinitely! It doesn't come out of that at all.
I used qdebug inside the implementation of the 3 slots to check whether it is entering them or not, and surprisingly none of the slots gets called. Why is that so?
If I remove the comments for .wait then the program pauses.
What is wrong in this method? I want to avoid that extra class as my program is very small.
while(lett.isRunning())
{
//qDebug() << "Still Running!";
}
lett.quit();
Terribly wrong. The current thread is busy waiting and will be eating all the time. But this is not your problem. Your problem is certainly that the main event loop has probably not started yet, ie you didn't do QApplication.exec() yet.
Qt uses events to start threads, and when you do use movetoThread, start, specific events are queued in the current thread (ie the thread executing these methods). If the main event loop has already started, then will be processed as soon as they can. But in your case I bet that you main function is :
int main(){
QApplication app();
myclass onlyclassIwanttomake;
onlyclassIwanttomake.dowork();
app.exec(); <----HERE!!!
}
The thread will be started when the main thread executes app.exec();. When you are busy waiting, you are preventing the main thread to process the events required to start your
events.
EDIT: Well, another issue is that
lett.start();
latt.start();
pltt.start();
start 3 threads which are started, and stay idle forever. They are not doing anything, but they are running (even if you remove your loop).
This is a entry written about Qt threading. Please take the time to read it.