To fork or not to fork


#1

Hello Jules and Juce users!

I have encountered some unexpected troubles while porting Windows application to MacOS. And i guess all other Unix-based systems too

The application is made of 2 processes:

  1. First one is a GUI made with Juce that launches the second one
  2. Second is a proprietory application with localhost socket interface.
    The protocol description is public so i have a GUI implementing the interface in a convinient form.

I had no problems on Windows using CreateProcess inside JUCE_WINDOWS defines of the first app to start the second one. But there is a big problem on Mac .
I can’t run fork in the first application due to MacOS fatal error (forking multi-threaded process). I tried to fork in the constructor of implemetation class that is derived from JUCEApplication.

class AppClass: public JUCEApplication
{
  public:
  AppClass()
  {
      int cpid =fork(); //forking in multi-threaded process
      if(cpid == 0){
        /* exec() something in child process */
        exit(0);
      }
  }
 ...
}

Where is the best place to fork in Juce application?
Or should i make a third application that starts the first and the second application as its child processes?

Thanks in advance


#2

I wouldn’t really recommend forking at all… (Is it even possible in windows?) Maybe just make your first process launch the second one and communicate between them?


#3

you got the idea. but i want the GUI appplication made with Juce launch the second (console) and communicate

There are a lot of reasons to keep the propriotry application unchangeable. But i did have the same thought yesterday.

There is no reason to fork in windows. It is possible to use other way like CreateProcess() or _spawnl()
I guess i’ve found a good solution for GCC. Why can’t i fork from gui apllication process before Juce initialization?

//don't use the default macro
/* START_JUCE_APPLICATION(AppClass) */ 

static JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication() 
{ 
  return new AppClass(); 
} 
//==============================================================================
#if defined (JUCE_GCC)
#if JUCE_MAC
#define SUBPROCESS "child_app"
#endif
int main (int argc, char* argv[]) 
{ 
  JUCE_NAMESPACE::JUCEApplication::createInstance = &juce_CreateApplication; 
  const char* const argv[] = {  SUBPROCESS , "-w", "-i", "-a", NULL };
  const int cpid = fork();
  if (cpid == 0)  
  { // Child process    
    if (execve (argv[0], (char**) argv, 0) < 0)
    exit (0);
  }
  return JUCE_NAMESPACE::JUCEApplication::main (argc, (const char**) argv); 
}
#elif JUCE_WINDOWS
#define FXS_EXE "child_app.exe"
#include <process.h>
int __stdcall WinMain (int, int, const char*, int) 
{ 
  bool showWindow = false;
  JUCE_NAMESPACE::JUCEApplication::createInstance = &juce_CreateApplication; 

  _spawnl( showWindow ? P_NOWAIT:_P_DETACH,
           SUBPROCESS ,  
           SUBPROCESS , "-w", "-i", "-a", NULL );
   return JUCE_NAMESPACE::JUCEApplication::main (JUCE_NAMESPACE::PlatformUtilities::getCurrentCommandLineParams()); 
}
#endif

it seems to work the way i wanted :slight_smile: