Qt World Summit: Submit your Presentation

The difference between QProcess::start() and QProcess::startDetached() for the called application itself

  • What is the difference in using QProcess::start () and QProcess::startDetached () for the called application itself?
    I observe the different behavior of the called application when using these methods. I call avrdude.exe with some arguments and the result differs when using the QProcess :: start(), while the result of the work QProcess :: startDetached() is exactly the same as if I used avrdude.exe directly. Why is this happening?

  • @Andrey-Vasilyev said in The difference between QProcess::start() and QProcess::startDetached() for the called application itself:

    ents and the result differs when using the QProcess :: start(), while the result of the work QProcess :: startDetached() is exactly the same as if I used avrdude.exe directly. Why is this

    Hi @Andrey-Vasilyev and Welcome!

    First, from the Qt5.11 docs for startDetached:
    "Starts the program set by setProgram() with arguments set by setArguments() in a new process, and detaches from it. Returns true on success; otherwise returns false. If the calling process exits, the detached process will continue to run unaffected.

    Unix: The started process will run in its own session and act like a daemon.

    The process will be started in the directory set by setWorkingDirectory(). If workingDirectory() is empty, the working directory is inherited from the calling process.

    Note: On QNX, this may cause all application threads to temporarily freeze.

    If the function is successful then *pid is set to the process identifier of the started process. Note that the child process may exit and the PID may become invalid without notice. Furthermore, after the child process exits, the same PID may be recycled and used by a completely different process. User code should be careful when using this variable, especially if one intends to forcibly terminate the process by operating system means."

    What this really means, is that it is not in your control or in your process tree. Your application can end and a QProcess started with startDetached will continue to stay running. All other aspects of QProcess should still work the same.

    Using startDetached is great if you want to start tasks that you wish to keep running after you exit. Just note that the process-id returned can be re-used by the OS so it is not good to use just that to manage your tasks.

  • @Andrey-Vasilyev
    One thing which differs is that the called program does not inherit its i/o file descriptors from the calling program, and redirected from/to it, which is normally what happens from start(). I haven't looked, but startDetached() processes are likely to have no initial stdin/stdout/stderr, and won't inherit a console if called from there. That might affect the behaviour you are seeing.

    The called process is not terminated if the calling process exits. But I don't see why that would be likely to produce the difference you see.

    There will be further OS-specific differences.

    Is your avrdude.exe a console or UI application? For example, if it's expecting its stdin to be coming from a terminal, it will be disappointed...

  • Hi @JonB and @Buckwheat
    Thanks for the response!

    Avrdude.exe is a console application.
    The code below is where I start the process. It does not require input, all the necessary information is passed in the arguments

    void avrdudeHandler::init()
        avrdude = new QProcess;

    This is the result of the QProcess::start ()

    avrdude.exe: AVR device initialized and ready to accept instructions
    Reading | ################################################## | 100% 0.00s
    avrdude.exe: Device signature = 0x1e940b (probably m168p)
    avrdude.exe done.  Thank you.

    And this is the result of the QProcess::startDetached()

    avrdude.exe: AVR device initialized and ready to accept instructions
    Reading |                                                    | 0% 0.00s
    Reading | #################                                  | 33% 0.00s
    Reading | #################################                  | 66% 0.01s
    Reading | ################################################## | 100% 0.01s
    avrdude.exe: Device signature = 0x1e940b (probably m168p)
    avrdude.exe: safemode: Fuses OK (E:F9, H:D5, L:F7)
    avrdude.exe done.  Thank you.

    I'm think that avrdude.exe can't execute one more instance or thread when using QProcess::start ()

  • Hi @Andrey-Vasilyev ,

    I really looks like it is sending "Reading | <some stuff> | <status> <carriage-return>" each time it updates the status and the writer is thinking it is <carriage-return><line-feed> or something. Have you tried reading in the data yourself and inspecting the strings?

    I typically do not write to files but read the data and either update status or log as it goes along.

  • @Buckwheat

    Yes, I tried to accept output through qdebug ().

        connect(avrdude, &QProcess::readyReadStandardOutput, [=](){qDebug() << avrdude->readAllStandardOutput();});

    Even when avrdude.exe starts with the -l option for it to store the data into its own log, the situation is the same.

  • Hi @Andrey-Vasilyev ,

    It really looks like a <cr> vs. <cr><lf> issue. What did the trailing chars look like? I am no expert on QProcess inner workings, but I wonder if for some reason, since startDetached acts like a daemon, the standard output cannot determine if it processes end-of-line type sequences properly.

    Is the output in one format or another an issue? If you need to NOT wait for the app, you could always use signals to be notified when the app finishes, etc. (like you did the output) and just use QProcess::start.

  • @Andrey-Vasilyev
    I'm not really understanding what your problem is exactly!

    Is it the fact that some progress output was over one line in one case and 4 lines in the other?

    Is it that only the startDetached() produces the line:

    avrdude.exe: safemode: Fuses OK (E:F9, H:D5, L:F7)

    while the result of the work QProcess :: startDetached() is exactly the same as if I used avrdude.exe directly

    What does "used avrdude.exe directly" mean? Run it from a command prompt? Run it from Windows Run? Double-click a shortcut? Something else?

    And your invoking Qt application, what is that? Does it have a UI or is it console?

  • Hi @JonB

    The problem is in the different behavior of the called process, I'm trying to understand why.
    And the difference is just this line below, this is what I need from avrude.exe

    avrdude.exe: safemode: Fuses OK (E:F9, H:D5, L:F7)

    The result of the QProcess :: startDetached() is correct and coincides with the result of running avrude.exe from the command prompt.
    My application simply runs an avrdude.exe with different parameters depending on which button you clicked.

    I think I solved the problem, but did not understand why it was happening at all.
    When I start the avrdude.exe using QProcess::start() with the -s option in arguments, everything works as it should.
    Below is the description of the -s option from the avrdude documentation:

    Disable safemode prompting. When safemode discovers that one or more fuse
    bits have unintentionally changed, it will prompt for conrmation regarding
    whether or not it should attempt to recover the fuse bit(s). Specifying this
    flag disables the prompt and assumes that the fuse bit(s) should be recovered
    without asking for conrmation rst.

    As I understand from this description avrdude waiting for confirmation in stdin, and the option -s disables the request for this confirmation.

  • @Andrey-Vasilyev
    Like I said earlier, the major difference between start() & startDetached() is the state of stdin/out/err file handles on entry to the sub-process, and is the only thing likely to be "noticed by"/affect it.

    • start(): child's standard I/O descriptors attached to parent (via anonymous pipe). Read http://doc.qt.io/qt-5/qprocess.html#ProcessChannelMode-enum etc. From parent QProcess has methods to write to child's stdin and/or read from child's stdout/err. Child sees these descriptors as open for read/write.

    • startDetached(): child's standard I/O descriptors not attached to parent . Presumably they are closed (e.g. child read stdin => EOF). Only setStandardInput/Output/ErrorFile() can be used to cause them to read from/write to files.

    You'd have to understand how this affects your AVR Dude program to know what that would cause it to do, and why some -s argument would address the situation. The stdin situation will doubtless affect its "prompt for confirmation regarding".

    Purely at a guess, if you want your start() to behave same as your startDetached() for your particular avrdude child try http://doc.qt.io/qt-5/qprocess.html#closeWriteChannel. OTOH, if you want to be able to type in the console where you run your Qt (console) app from and have that go to the sub-process, look at http://doc.qt.io/qt-5/qprocess.html#InputChannelMode-enum and try setting it to QProcess::ForwardedInputChannel.

    I trust the above clarifies/helps!

  • Thanks @JonB !
    Your advice was very helpful

    The source code of avrdude.exe contains a line of code:

      if (isatty(STDIN_FILENO) == 0 && silentsafe == 0)
        safemode  = 0;       /* Turn off safemode if this isn't a terminal */

    silentsafe depends on -s argument, and the function isatty(STDIN_FILENO) always returns 0 when process started using QProcess::start(), because of child's standard I/O descriptors attached to parent via pipe.
    Below is the description of this function:

    The `int isatty(int fildes)`  function shall test whether fildes, an open file descriptor, is associated with a terminal device.

  • @Andrey-Vasilyev
    Yes, I expected your avrdude.exe child to be using isatty(0) to decide whether to prompt interactively or not. But I would have expected startDetached()'s stdin to be closed, if anything, and therefore not isatty(0) too, so not sure why that is differing for what you see under start(). However, the overall is it's probably just the difference in stdin which is somehow producing the different behaviour from AVR dude guy.

    It should be the case that when choosing between them: if you want "nothing to do" with the child, use startDetached(); if you have something to do with it, like communicating with it or waiting for it to finish, use start().

Log in to reply