1

I have written a program where I create a thread in the main and use system() to start another process from the thread. Also I start the same process using the system() in the main function also. The process started from the thread seems to stay alive even when the parent process dies. But the one called from the main function dies with the parent. Any ideas why this is happening.

Please find the code structure below:

void *thread_func(void *arg)
{
     system(command.c_str());        
}

int main()
{
    pthread_create(&thread_id, NULL, thread_func, NULL);
    .... 
    system(command.c_str());
    while (true)
    {
        ....
    }
    pthread_join(thread_id, NULL);
    return 0;
}
kiner_shah
  • 3,939
  • 7
  • 23
  • 37
Yash Kapoor
  • 93
  • 2
  • 12
  • Your definition for `thread_func()` is not correct - it lacks an argument. See [link](https://en.wikipedia.org/wiki/POSIX_Threads#Example) which shows an example. – kiner_shah Aug 05 '18 at 15:25
  • @kiner_shah This is just a skeleton. I do have the thing in my actual code – Yash Kapoor Aug 06 '18 at 09:09

2 Answers2

5

My suggestion is: Don't do what you do. If you want to create an independently running child-process, research the fork and exec family functions. Which is what system will use "under the hood".

Threads aren't really independent the same way processes are. When your "main" process ends, all threads end as well. In your specific case the thread seems to continue to run while the main process seems to end because of the pthread_join call, it will simply wait for the thread to exit. If you remove the join call the thread (and your "command") will be terminated.

There are ways to detach threads so they can run a little more independently (for example you don't have to join a detached thread) but the main process still can't end, instead you have to end the main thread, which will keep the process running for as long as there are detached threads running.


Using fork and exec is actually quite simple, and not very complex:

int pid = fork();
if (pid == 0)
{
    // We are in the child process, execute the command
    execl(command.c_str(), command.c_str(), nullptr);

    // If execl returns, there was an error
    std::cout << "Exec error: " << errno << ", " << strerror(errno) << '\n';

    // Exit child process
    exit(1);
}
else if (pid > 0)
{
    // The parent process, do whatever is needed
    // The parent process can even exit while the child process is running, since it's independent
}
else
{
    // Error forking, still in parent process (there are no child process at this point)
    std::cout << "Fork error: " << errno << ", " << strerror(errno) << '\n';
}

The exact variant of exec to use depends on command. If it's a valid path (absolute or relative) to an executable program then execl works well. If it's a "command" in the PATH then use execlp.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 1
    I concur with answer. Additionally, if all you need is to capture output of a command, and you don't need it to run after main process dies, this is useful: https://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c-using-posix – Erik Alapää Aug 02 '18 at 08:55
  • @ErikAlapää Good link. But the accepted answer do have a flaw with the `while (!feof(...))` loop (as pointed out in the comments). – Some programmer dude Aug 02 '18 at 09:00
  • Don't I need a double fork, as I want the parent process to continue and not wait for the child process. – Yash Kapoor Aug 02 '18 at 09:01
  • @YashKapoor Unless you want to get the exit-status of the child process, you never need to wait for it. If the child-process becomes orphaned, the "init" process will take over as parent and reap it when the child-process ends. – Some programmer dude Aug 02 '18 at 09:03
  • @Someprogrammerdude I tried the above code sample you posted. So, whenever I kill the parent process with Ctrl+C, the child process also dies – Yash Kapoor Aug 02 '18 at 09:38
  • I added the following condition under (pid==0) and the child becomes independent. **if (setsid() < 0) return false;** – Yash Kapoor Aug 02 '18 at 09:43
  • @YashKapoor It has to do with *process groups*. – Some programmer dude Aug 02 '18 at 09:45
0

There are two points here that I think you've missed:

First, system is a synchronous call. That means, your program (or, at least, the thread calling system) waits for the child to complete. So, if your command is long-running, both your main thread and your worker thread will be blocked until it completes.

Secondly, you are "joining" the worker thread at the end of main. This is the right thing to do, because unless you join or detach the thread you have undefined behaviour. However, it's not what you really intended to do. The end result is not that the child process continues after your main process ends... your main process is still alive! It is blocked on the pthread_join call, which is trying to wrap up the worker thread, which is still running command.

In general, assuming you wish to spawn a new process entirely unrelated to your main process, threads are not the way to do it. Even if you were to detach your thread, it still belongs to your process, and you are still required to let it finish before your process terminates. You can't detach from the process using threads.

Instead, you'll need OS features such as fork and exec (or a friendly C++ wrapper around this functionality, such as Boost.Subprocess). This is the only way to truly spawn a new process from within your program.

But, you can cheat! If command is a shell command, and your shell supports background jobs, you could put & at the end of the command (this is an example for Bash syntax) to make the system call:

  • Ask the shell to spin off a new process
  • Wait for it to do that
  • The new process will now continue to run in the background

For example:

const std::string command = "./myLongProgram &";
//                                           ^

However, again, this is kind of a hack and proper fork mechanisms that reside within your program's logic should be preferred for maximum portability and predictability.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055