3

I am writing a small updater utility that is being called from the main program. The main program terminates right after the call and lets the updater copy all the updated files and then it should re-launch the main program. However that last bit is starting to give me a headache.

I can run the program with std::system (I know, unsafe, but portable) just fine but then the updater just hangs there waiting for the main program to finish. I was searching for ways to make the call fire & forget and the threads seems like the best idea.

However this:

std::system("app");

hangs the updater as it waits for return from system. Whereas this:

std::thread(std::system, "app").detach();

nor variant

std::thread t(std::system, "app");
t.detach();

seem to do anything. But when I join the thread with:

std::thread t(std::system, "app");
t.join();

it does run the app but still waits for its return just like in the original code. Why can't the detached thread run the app?

Resurrection
  • 3,916
  • 2
  • 34
  • 56
  • 1
    What level of portability do you need (i.e. which platforms are of interest)? – Jason R Sep 18 '15 at 19:48
  • @JasonR The main app is a Qt app and I am targeting 3 Qt platforms: desktop, linux and mac... – Resurrection Sep 18 '15 at 19:53
  • 1
    Is QProcess unsuitable? – Nicolas Holthaus Sep 18 '15 at 20:08
  • @NicolasHolthaus Unfortunately yes. I cannot use statically built Qt so any Qt based updater would itself rely on Qt. Therefore I need to either close the Qt app (that used QProcess for calling the updater) and use non-Qt external updater to do the job and re-launch the Qt app or maintain two Qt deployments (one for the app and one for the updater) and update both when updating either. I figured external non-Qt app would be better solution. – Resurrection Sep 18 '15 at 20:10

2 Answers2

2

Any thread, whether detached or not, will die if its process finishes(on most systems). Give some time before the updater end execution, and the thread may be able to actually make the call:

#include <chrono>
#include <cstdlib>
#include <thread>

void do_app() {
  std::system("app");
}

int main() {
  std::thread(do_app).detach();
  std::this_thread::sleep_for(std::chrono::seconds(2));
} 
Not a real meerkat
  • 5,604
  • 1
  • 24
  • 55
  • Brilliant. :-) It actually did the trick... I haven't thought this would be an issue as I have read confusing information about "what happens to detached threads after main returns" with some claiming it is killed (as is apparently the case) and some it is not. – Resurrection Sep 18 '15 at 20:08
  • This is because the standard actually doesn't define what happens to a detached thread when the main program's execution finishes: Each system may do anything. It's certainly possible that some exotic system keeps the thread executing. Most don't. – Not a real meerkat Sep 18 '15 at 20:12
1

I would just use ifdef blocks around the different implementations. For Windows you can use CreateProcess, linux (and probably Mac) supports POSIX popen / fork methods.

std::system does not really make your program portable, usually the syntax for invoking things on the shell differs slightly from platform to platform and you end up with platform dependent code anyways.

Here is a detailed tutorial on how to do it in Linux: http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

And for Windows: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx

ventsyv
  • 3,316
  • 3
  • 27
  • 49
  • Thanks, I will look into it. The different call methods could be solved by passing the actual command to call from the main program when the updater is called. – Resurrection Sep 18 '15 at 20:02