Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QProcess -- working QIODevice::Unbuffered, or adjustable buffersize for faster access to stdout
Qt 6.11 is out! See what's new in the release blog

QProcess -- working QIODevice::Unbuffered, or adjustable buffersize for faster access to stdout

Scheduled Pinned Locked Moved General and Desktop
26 Posts 15 Posters 34.2k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    mbroadst
    wrote on last edited by
    #15

    This may seem like a silly question, but have you properly started the thread? I've seen some very strange behavior mixing QProcess with threads, you might be hung up somewhere else.

    Just a thought.

    1 Reply Last reply
    0
    • I Offline
      I Offline
      infoctopus
      wrote on last edited by
      #16

      dlonie, also redirecting stdout could be of some use

      Qt rulez

      1 Reply Last reply
      0
      • I Offline
        I Offline
        infoctopus
        wrote on last edited by
        #17

        @template<class Elem = char, class Tr = std::char_traits<Elem>>

        class StdRedirector : public std::basic_streambuf<Elem, Tr>
        {
        /**

        • Callback Function.
          /
          typedef void (pfncb)(const Elem, std::streamsize _Count, void
          pUsrData);

        public:
        /**

        • Constructor.
        • @param a_Stream the stream to redirect
        • @param a_Cb the callback function
        • @param a_pUsrData user data passed to callback
          /
          StdRedirector(std::ostream& a_Stream, pfncb a_Cb, void
          a_pUsrData):
          m_Stream(a_Stream), m_pCallbackFunction(a_Cb), m_pUserData(a_pUsrData)
          {
          //redirect stream
          m_pBuffer = m_Stream.rdbuf(this);
          };

        /**

        • Destructor.
        • Restores the original stream.
          */
          ~StdRedirector()
          {
          m_Stream.rdbuf(m_pBuffer);
          }

        /**

        • Override xsputn and make it forward data to the callback function.
          /
          std::streamsize xsputn(const Elem
          _Ptr, std::streamsize _Count)
          {
          m_pCallbackFunction(_Ptr, _Count, m_pUserData);
          return _Count;
          }

        /**

        • Override overflow and make it forward data to the callback function.
          */
          typename Tr::int_type overflow(typename Tr::int_type v)
          {
          Elem ch = Tr::to_char_type(v);
          m_pCallbackFunction(&ch, 1, m_pUserData);
          return Tr::not_eof(v);
          }

        protected:
        std::basic_ostream<Elem, Tr>& m_Stream;
        std::streambuf* m_pBuffer;
        pfncb m_pCallbackFunction;
        void* m_pUserData;
        };

        ...

        void outcallback(const char* ptr, std::streamsize count, void* pTextEdit)
        {
        (void) count;
        QTextEdit* p = static_cast<QTextEdit*>(pTextEdit);
        p->append(ptr);
        }
        ...
        QTextEdit *teStdCout = new QTextEdit(wParent);
        m_stdRedirector = new StdRedirector<>(std::cout, outcallback, teStdCout);
        @

        Qt rulez

        1 Reply Last reply
        0
        • K Offline
          K Offline
          kreyszig
          wrote on last edited by
          #18

          bump.. i get the same behaviour. the signal readyReadStandardOutput () only appears to be emitted once a Qt buffer somewhere is filled. I know my process is writing frequent lines but get the output in chunks.

          Is there any resolution since 2010?

          1 Reply Last reply
          0
          • V Offline
            V Offline
            vsajip
            wrote on last edited by
            #19

            I think the problem is caused by buffering in the external program. Most programs written in C will buffer unless their output stream is a tty. When it isn't, you have to fake it using something like unbuffer (on Unix/Linux - part of the expect package - http://expect.sourceforge.net - which IIUC works by faking tty behaviour).

            1 Reply Last reply
            0
            • P Offline
              P Offline
              phlucious
              wrote on last edited by
              #20

              In the QProcess external program, how are you outputting the text to be read in?

              I had a similar issue with my QProcess. When I output to stdout, the readyRead() signal wouldn't emit until after it was already finished since I didn't have to output very much text. I found this link (http://www.lubby.org/ebooks/qtconsoleapp2/qtconsoleapp2.html) to be very helpful for outputting to stdout.

              If you don't want to read the link, stdout (or the QTextStream, if you went that route) has a built-in buffer that needs to be flushed manually to trigger the readyRead() signal. If your output looks like this:

              @QTextStream o(stdout);
              o << "Line of text here";@

              then readyRead() won't trigger unless you do this thousands of times or the QProcess finishes. I've found two options that work, depending on your implementation:

              @QTextStream o(stdout);
              o << "Line of text here" << std::endl;@

              or

              @QTextStream o(stdout);
              o << "Line of text here\n";
              o.flush();@

              Either way, you will trigger the stdout buffer to be flushed and readyRead() should trigger. As I understand it (I'm no expert), "std::endl" is the same as "\n" except that it also triggers a flush in addition to starting a new line. I prefer the second method so that I don't get extra newline characters floating around.

              Hope that helps if anyone runs into this issue.

              1 Reply Last reply
              0
              • J Offline
                J Offline
                joonhwan
                wrote on last edited by
                #21

                [quote author="Gerolf" date="1291544359"]Have you read the documentation? It states:

                bq. bool QIODevice::canReadLine () const [virtual]
                Returns true if a complete line of data can be read from the device; otherwise returns false.
                Note that unbuffered devices, which have no way of determining what can be read, always return false.
                This function is often called in conjunction with the readyRead() signal.

                I f you look at the code:
                @
                m_process->start(command, QProcess::Unbuffered | QProcess::ReadWrite);
                @

                Your device is uinbuffered, so canReadLine always returns false....[/quote]

                (Though this post quite old) I'd like to address a issue(or share info if possible) on this topic becuase I think I'm solving the similar problem described here.

                QProcess has internal two ring buffers(one for stdout and the other for stderr) of which canReadLine is called and seem to be able to return 'true' even with QProcess's unbuffered flag(At least in my following code). see following QProcess::canReadLine()

                @
                bool QProcess::canReadLine() const
                {
                Q_D(const QProcess);
                const QRingBuffer *readBuffer = (d->processChannel == QProcess::StandardError)
                ? &d->errorReadBuffer
                : &d->outputReadBuffer;
                return readBuffer->canReadLine() || QIODevice::canReadLine();
                }
                @

                I'm having no deep understand of QProcess and QRingBuffer's implementation.
                Here's my code that sends one line of command to spawed process and get one line of response.
                I could get true value from canReadLine and it seems to work as expected. But I'd appreciate if anyone points out any problem in this code nonetheless.

                @
                QString program = QString::fromLocal8Bit("pcomCmd.exe");
                m_process = new QProcess(this);
                m_process->setReadChannel(QProcess::StandardOutput);
                m_process->start(program, QStringList(), QIODevice::ReadWrite | QIODevice::Unbuffered);
                if (m_process->waitForStarted()) {
                connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(handlePcommCmdOuput()));
                } else {
                killPcommCmd();
                }
                @

                and then call following function to send to command and get response.

                @
                void MainWindow::writeAndReadResponse(const QString& _cmd)
                {
                QString cmd = _cmd + QString("\n");
                m_process->write(cmd.toLocal8Bit());

                m_log->appendPlainText(QString("cmd> ") + cmd);

                const int WAIT_TIME = 1000000;

                QElapsedTimer timer;
                timer.start();
                while (!timer.hasExpired(WAIT_TIME)) {
                m_process->waitForReadyRead(WAIT_TIME-timer.elapsed());
                if (m_process->canReadLine()) {
                QByteArray arr = m_process->readAll();
                m_log->appendPlainText(arr); // HERE I GOT TEXT LINE IN MY QPlainTextEdit widget.

                // do something according to arr

                break;
                }
                }
                }
                @

                joonhwan at gmail dot com

                1 Reply Last reply
                0
                • H Offline
                  H Offline
                  halfgaar
                  wrote on last edited by
                  #22

                  An old thread, but for the record: I had a similar problem with a Python script outputting lines that didn't show up in the QProcess until the python scripot ended. The issue was buffered output in Python. When I start it with the -u flag, it did work.

                  1 Reply Last reply
                  0
                  • L Offline
                    L Offline
                    Lumbricus
                    wrote on last edited by
                    #23

                    Ran into the same problem. Was running external c code and the readReady() signal would only fire when the StdOut buffer was full enough or after some time eg. 30sek. So i was not recieving the Output in realtime.

                    Since i had access to the external code. I disabled buffering for the output.

                    [code]
                    setbuf(stdout, NULL);
                    printf("Testoutput \n");
                    [/code]

                    after this modification the readReady() Signal fired everytime printf was used in external program.

                    regards

                    1 Reply Last reply
                    0
                    • H Offline
                      H Offline
                      Haponov
                      wrote on last edited by
                      #24

                      Same problem met - doing "hcitool -i hci0 lescan" which is quite interactive and does not seem to buffer stdout (e.g. I don't have this problem http://www.spinics.net/lists/linux-bluetooth/msg55523.html while redirecting to file) - I can read data from QProcess once per 4-10 seconds!

                      here's code:

                      void Tracer::start()
                      {
                       m_Process = new QProcess();
                       m_Process->setReadChannel(QProcess::StandardOutput);
                       connect(m_Process, SIGNAL(readyReadStandardOutput()), SLOT(readTracer()));
                       QString command = QString("stdbuf -oL hcitool -i hci0 lescan --duplicates");
                       m_Process->start(command, QProcess::Unbuffered | QProcess::ReadWrite);
                      }
                      
                      void Tracer::readTracer()
                      {
                       if (m_Process)
                       {
                           for (int i=0; i<200; ++i)
                           {
                               m_Data.append(m_Process->readLine());
                               if (m_Data.isEmpty())
                              {
                                 if(i==0)
                                   {qDebug()<<"empty"<<QDateTime::currentDateTime().toString(QString("[hh:mm:ss]")).toUtf8(); return;}
                                   else
                                   {qDebug()<<"last line was "<<i; return;}
                               }
                               m_Data.clear();
                               m_Data.append(m_Process->readLine(18));
                                   qDebug()<<m_Data<<QDateTime::currentDateTime().toString(QString("[hh:mm:ss:ms]")).toUtf8();
                          }
                               m_Data.clear();
                       }
                      }
                      
                      

                      I started with "hcitool -i hci0 lescan " and then came up to "stdbuf -oL hcitool -i hci0 lescan --duplicates" - no difference

                      1 Reply Last reply
                      0
                      • H Offline
                        H Offline
                        Haponov
                        wrote on last edited by Haponov
                        #25

                        looking through "hcitool lescan" source code here http://code.metager.de/source/xref/linux/bluetooth/bluez/tools/hcitool.c#print_advertising_devices

                        the output to stdout is made with

                        		printf("%s %s\n", addr, name);
                        

                        that's on line 2471.

                        If I write smth like

                        std::flush();
                        

                        or rather fflush(stdout)
                        after this line - will this help? or maybe

                        setbuf(stdout, NULL); 
                        

                        ?
                        and then I should compile it somehow...

                        1 Reply Last reply
                        0
                        • H Offline
                          H Offline
                          Haponov
                          wrote on last edited by
                          #26
                          fflush(stdout) 
                          

                          did its job! I receive lines in real-time, lots of times per second.

                          Well, of course it'd been oh so much better if QProcess could flush output of its child-process

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved