使用system()创建独立的子进程

时间:2018-08-02 07:51:49

标签: c++ multithreading pthreads fork system-calls

我编写了一个程序,在其中创建了一个主线程,并使用system()从该线程启动另一个进程。同样,我也使用main函数中的system()开始相同的过程。即使父进程死了,从线程启动的进程似乎仍然保持活动状态。但是从主函数调用的那个函数与父函数死亡。任何想法为什么会这样。

请在下面找到代码结构:

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;
}

2 个答案:

答案 0 :(得分:3)

我的建议是:不要做自己想做的事情。如果要创建独立运行的子进程,请研究forkexec family函数。 system将在“幕后使用”。

线程并不是真正独立于进程。当您的“主”进程结束时,所有线程也会结束。在您的特定情况下,线程似乎继续运行,而主进程似乎由于pthread_join调用而结束,它只会等待线程退出。如果删除联接调用,则线程(和您的“命令”)将终止。

有多种方法可以分离线程,以便它们可以更独立地运行(例如,您不必加入分离的线程),但是主进程仍然无法结束,相反,您可以必须结束主线程 ,只要有分离的线程在运行,该线程就可以使进程一直运行。


使用forkexec实际上很简单,也不是很复杂:

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';
}

要使用的exec的确切变体取决于command。如果它是可执行程序的有效路径(绝对路径或相对路径),则execl可以很好地工作。如果它是PATH中的“命令”,则使用execlp

答案 1 :(得分:0)

我想您错过了两点:

首先,system是一个同步呼叫。这意味着您的程序(或至少调用system的线程)等待,以使子进程完成。因此,如果您的command长时间运行,则主线程和辅助线程都将被阻塞,直到完成为止。

第二,您正在main末尾“加入”工作线程。这是正确的做法,因为除非您加入或分离线程,否则您将无法定义行为。但是,这并不是您真正想做的。最终结果不是子进程在您的主进程结束之后继续运行...您的主进程仍然存在!它在pthread_join调用中被阻止,该调用正在试图包装仍在运行command的工作线程。

通常,假设您希望产生一个与主进程完全无关的新进程,则线程不是实现该进程的方法。即使您要分离线程,它仍然属于您的进程,并且仍然需要在进程终止之前让它完成。您无法使用线程从进程中分离出来。

相反,您将需要诸如forkexec之类的OS功能(或围绕此功能的友好C ++包装器,如Boost.Subprocess)。这是从程序内部真正产生新进程的唯一方法。

但是,您可以作弊!如果command是Shell命令,并且您的Shell支持后台作业,则可以将&放在命令末尾(这是Bash语法的示例)以进行system调用:

  • 询问外壳以剥离新进程
  • 等待它这样做
  • 新流程现在将继续在后台运行

例如:

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

不过,这又是一种hack和适当的fork机制,驻留在 内,为最大的可移植性和可预测性,应该首选程序的逻辑。

相关问题