1

I am deploying a Qt application from a USB drive on windows. The application takes a while to cold start (~10s). I want to display some splash screens to keep the user patient while it loads.

I first tried putting the splash screens in the main thread, they did not appear for ~10s. Whatever library is being cached must be still loading before the splash screens appear.

I then tried to move splash screens to another process and start it using QProcess::start(). Once again there is a ~10s delay and then both my application and the splash screens are appearing simultaneously.

Finally I tried making a splash screen process launch my primary application using QProcess::start(). In this case the splash screens appear well before the primary application as desired, but the trouble is I would like two things 1) the primary application to outlive the splash screens, 2) the primary application to inform the splash screens that it is done loading via stdout and QProcess:readAllStandardOutput() so the splash screen can kill itself.

It seems that this is not possible with QProcess::start, QProcess::execute, and QProcess::startDetached. When using startDetached QProcess::readAllStandardOutput() won't work because QProcess::startDetached is static.

When using QProcess::start and QProcess::execute my main application should not outlive the splashscreens, which oddly enough is not the case and I have posted a separate question asking why that might be (Attached child QProcess outliving parent). Since the documentation leads me to believe this should not happen I do not want to rely on this behavior.

Does anyone know how I can safely start a QProcess that outlives its parent AND can communicate with it?

Community
  • 1
  • 1
user3528438
  • 2,737
  • 2
  • 23
  • 42
  • I don't think you can do this without introducing memory leaks. The `QProcess` destructor waits for the child process to finish before returning, so you'd need to create it on the heap and _purposefully_ not delete it. But I think you should figure out what's causing your huge startup time, and work around that. Qt applications are usually pretty fast to load, even on Windows machines. – bnaecker Mar 23 '16 at 01:58
  • Memory is easy to handle by connecting the `finished` signal to the `deleteLater` slot. The huge start time is simply the huge amount of dependency on Qt dynamic libraries and the extremely low speed of storage media, based on the observation that only a "cold" start is slow (first launch after storage media is attached to the system). The application and all supporting libraries are stored in a USB mass storage device with average read bandwidth around 3MB/s. – user3528438 Mar 23 '16 at 02:29
  • Fair enough on the startup time. But your suggestion about connecting the `deleteLater` slot won't work. That connection will be made and processed in the event loop corresponding to a now-killed process. How could it be delivered? Its event loop is now gone. Said another way, the `QProcess` object lives in the process that will be killed, not in the process it creates. On another point, are you using `QSplashScreen`? The docs have an example for getting the screen going before the main application event loop starts up. – bnaecker Mar 23 '16 at 02:48
  • @bnaecker I would make the connection in the parent's context, basically right after it's `new`ed, so the parent's event would do it. However this only works and is only necessary when the `QProcess` is to be started with `QProcess::start()`, for `QProcess::startDetached()` is static and does not need an instance to call it with. The tricky thing is that you can not call `waitForFinished` if such connection is made because it may already be deleted when you are waiting and could cause a segfault. – user3528438 Mar 23 '16 at 03:07
  • @bnaecker And yes my current code is already using `QSplashScreen`. The problem is that if it's in the main function of the main app then it won't show until all dependencies are loaded which defeats the purpose of "to show something when the dynamic libraries are loading". – user3528438 Mar 23 '16 at 03:16
  • @bnaecker There are three different ways to do separate splash and main app into different processes, which hopefully can free the splash process from the library loading time of the main app, but each has its problem: 1)main process starts splash process, no speed improvement, because main function won't even enter until libraries are loaded; 2) splash process calls main thread non-detached, splash process can not die before main app dies 3) splash process calls main process detached, then stdio is also detached and IPC is hard to implement. – user3528438 Mar 23 '16 at 03:18
  • 1
    I think there are a few ways. 1. You can start child process as not detached and keep the launcher process running all the time the main app is running. Just hide the splash screen when you receive a stdio command from the child process. 2. Use detached child process with one of standard IPC tools, for example use `QLocalSocket/QLocalServer` pair. 3. Use detached process with some mediator file which you monitor in the launcher process and modify in the child process. – Evgeny S. Mar 23 '16 at 19:37
  • @EvgenyS. My colleague and I discussed this further and we reached the same conclusion: either detach the child and use another IPC method( as your suggestion 2 and 3), or maintain both processes but hide the existence of the splash screen process rather than killing it (as your suggestion 1). We tried the latter and it seem to work: we are able to hide the splash screen process from the user so well that it's not visible to the user unless in the task manager. We'll continue to test it on other OSes and see how it works. – user3528438 Mar 24 '16 at 00:08

0 Answers0