PDA

View Full Version : Problem quitting QThread that uses readLine



DiamonDogX
3rd February 2010, 19:55
I have a thread I run in my console app that allows the user to quit at any time by typing 'q' and pressing enter. The thread gracefully ends when the user does this because it breaks out of my loop and the run() function terminates. However, there are certain other situations in which I want to close the app (e.g. some event occurs), but I can't terminate the thread because it is always blocked on the readLine() call so I get a warning message upon quitting the app saying something like "Quit application while QThread still running..."

Is there a way around this to quit gracefully and not receive this warning?



class ConsoleReader : public QThread
{
public:
ConsoleReader( QObject * parent = 0 ) : QThread( parent )
{
QThread::setTerminationEnabled( true );
}
virtual void run()
{
QTextStream qin( stdin, QFile::ReadOnly );
forever
{
QString line = qin.readLine();
if( !line.isNull() )
{
if( line.toLower() == "q" )
{
break;
}
}
}
}
};

pitonyak
3rd February 2010, 21:49
I have not looked at the source code for readLine(), but, typically, the code waits until either a new line has been entered, or until the stream ends (ie, the user presses Ctrl+Z I think). In your case, neither occurs when the program ends, so this thread is left hanging I suppose.

When I do this sort of thing, I usually have a method such as isEndRequested and requestEnd. I implement this to be far more polite than the terminate slot in the QT thread class. Terminate just kills things regardless of what they are doing. In your code, when the program is requested to quit, I would then call requestEnd, and then wait for it to finish. If you do this, however, then your run method must notice and end quickly. Your run method would no longer use "forever", but instead, something more like this:

while (!isEndRequested()
{
if (data is available from the stream)
{
read_from_stream
}
else
{
sleep a bit
}
}
The QIODevice has methods available that can help. Things like bytesAvailable and watForReadyRead. The later will allow you to skip a thread sleep. The most difficult part here is that you must then accumulate the characters and process out lines by yourself.

pitonyak
4th February 2010, 17:43
I must admit. I have lost a lot of time trying to read directly from stdin in a simple Console application, all to no affect. My expectation was that I would be able to connect directly using a QFile using something like:

QFile f;
f.open(0, QFile::ReadOnly);
I failed just as horribly trying to use a text stream and then hitting the device directly from the stream. I have usually done this by going directly to the keyboard object, but this is very much NOT QT specific.
This claims to be a working example, that may work for you, but did not function in the context of my simple console application with no event loop and such
http://lists.kde.org/?l=kde-bindings&m=121113495705263&w=2