【问题标题】:Use system() to create independent child process使用 system() 创建独立的子进程
【发布时间】:2019-01-09 21:54:36
【问题描述】:

我编写了一个程序,我在主线程中创建一个线程并使用system() 从线程启动另一个进程。此外,我也在主函数中使用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;
}

【问题讨论】:

  • 您对thread_func() 的定义不正确 - 它缺少参数。请参阅link,其中显示了一个示例。
  • @kiner_shah 这只是一个骨架。我的实际代码中确实有这个东西

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


【解决方案1】:

我的建议是:不要做你该做的事。如果您想创建一个独立运行的子进程,请研究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

【讨论】:

  • 我同意答案。此外,如果您只需要捕获命令的输出,并且您不需要在主进程终止后运行它,这很有用:stackoverflow.com/questions/478898/…
  • @ErikAlapää 好链接。但是接受的答案确实存在 while (!feof(...)) 循环的缺陷(如 cmets 中所指出的那样)。
  • 我不需要双叉,因为我希望父进程继续而不是等待子进程。
  • @YashKapoor 除非您想获得子进程的退出状态,否则您永远不需要等待它。如果子进程成为孤立的,“init”进程将作为父进程接管,并在子进程结束时获得它。
  • @Someprogrammerdude 我尝试了您发布的上述代码示例。所以,每当我用 Ctrl+C 杀死父进程时,子进程也会死掉
【解决方案2】:

这里有两点我认为你错过了:

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

其次,您正在“加入”main 末尾的工作线程。这是正确的做法,因为除非您加入或分离线程,否则您有未定义的行为。然而,这并不是你真正想要做的。最终的结果不是子进程在你的主进程结束后继续......你的主进程还活着!它在 pthread_join 调用上被阻塞,该调用试图结束仍在运行的工作线程 command

一般来说,假设您希望生成一个与您的主进程完全无关的新进程,线程不是执行此操作的方法。即使你要分离你的线程,它仍然属于你的进程,你仍然需要让它在你的进程终止之前完成。您不能使用线程从进程中分离。

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

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

  • 要求 shell 分拆一个新进程
  • 等待它这样做
  • 新进程现在将继续在后台运行

例如:

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

然而,再一次,这是一种 hack 和适当的 fork 机制,驻留在您的程序逻辑中应该是首选,以获得最大的可移植性和可预测性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 2016-03-18
    • 2015-07-23
    • 2018-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多