10

I would like to read asynchronously from stdin with Qt. I don't want to use a separate thread or have to setup a timer to periodically check if the file descriptor has data. How can I do this?

László Papp
  • 51,870
  • 39
  • 111
  • 135
megazord
  • 3,210
  • 3
  • 23
  • 31
  • What's wrong with using a thread or polling? – Chris Mar 16 '12 at 16:56
  • Don't want to waste resources on the extra thread and have to deal with locking not if I can avoid it. I also don't want to waste cpu cycles when my app is idle. – megazord Mar 16 '12 at 17:10
  • 3
    Sounds to me like you're trying to optimize your code before seeing whether or not it actually needs to be. I'd say the thread approach is probably too complex, but polling periodically with a timer is pretty dang cheap. – Chris Mar 16 '12 at 18:53

6 Answers6

3

If you read the Qt documentation, it says you cannot do this because it is not portable. Why not use a TCP socket that should work assuming you have control over the other end. Worst case you can make a proxy application.

László Papp
  • 51,870
  • 39
  • 111
  • 135
Eric des Courtis
  • 5,135
  • 6
  • 24
  • 37
3

If you want to integrate stdin/stdout/stderr I/O with the QT event loop, you can either:

  1. Use a QSocketNotifier and do the I/O yourself with read(2) and write(2), or
  2. Get a QFile object and call bool QFile::open ( int fd, OpenMode mode ) to do Qt-style I/O with it.
Tustin2121
  • 2,058
  • 2
  • 25
  • 38
je4d
  • 7,628
  • 32
  • 46
2

Maybe this works for you:

https://github.com/juangburgos/QConsoleListener

Works like this:

#include <QCoreApplication>
#include <QDebug>

#include <QConsoleListener>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // listen to console input
    QConsoleListener console;
    QObject::connect(&console, &QConsoleListener::newLine, &a, [&a](const QString &strNewLine) {
        qDebug() << "Echo :" << strNewLine;
        // quit
        if (strNewLine.compare("q", Qt::CaseInsensitive) == 0)
        {
            qDebug() << "Goodbye";
            a.quit();
        }
    });

    qDebug() << "Listening to console input:";
    return a.exec();
}
2

If you are open to using boost, you could use the Asio library. A posix::stream_descriptor assigned to STDIN_FILENO works quite well. See also this answer.

Community
  • 1
  • 1
Sam Miller
  • 23,808
  • 4
  • 67
  • 87
2

Try using QSocketNotifier

QSocketNotifier * notifier = new QSocketNotifier( FDSTDIN, QSocketNotifier::Read );
connect(notifier, SIGNAL(activated(int)), this, SLOT(readStdin(int)));
Kamil Klimek
  • 12,884
  • 2
  • 43
  • 58
1

As Chris pointed out the best way would be to have a separate thread that would poll from the stdin and populate data for the display or processing thread to process.

Now you can certainly set up QTimer and set up a handler for the timeout() signal to read from stdin as well. The method of implementing is entirely up to you.

And for the second method you can take a look at QT's timer class documentation for an example on how to do this. One thing to remember would be to actually restart the timer once your processing is completed.

Karlson
  • 2,958
  • 1
  • 21
  • 48