【问题标题】:replace system and popen calls with calls that does not clone process memory用不克隆进程内存的调用替换 system 和 popen 调用
【发布时间】:2012-06-11 21:09:23
【问题描述】:

我正在编写对内存宽度和性能敏感的多线程服务器。因此,我需要标准system()popen() 调用的替代方案,它们不使用fork() 克隆通常需要太多时间的所有进程内存。

看来,需要先使用vfork(),然后再使用execve()

谁能帮我实现两个功能:

  • 替换system() 呼叫。 行为示例: 一个线程调用函数执行例如touch filename 并调用线程等待直到执行结束。 (所有其他线程必须继续工作)
  • 替换popen()调用行为示例:相同的行为,但需要获取命令的输出,例如ls -flags(此代码的替代方法:@987654321 @)

谢谢

【问题讨论】:

  • fork 进行了极大的优化,以避免对所有进程的内存进行大量复制;通常它是通过写时复制来实现的,因此除非绝对必要,否则实际上不会复制任何内存。你确定fork太慢了吗?
  • @templatetypedef 是的,3-4 天我在这里寻找解决方案,为什么我的服务器时不时显着减慢(14-30 秒)。现在我有 80% 的把握,那就是它的内存问题。我的服务器是~100-300mb,然后在需要200 mb的popen()调用中调用ffmpeg,所以,现在的父级不少于200 mb,并且似乎在popen()调用它的速度变慢了..不知道是谁写信给它,也许是系统问题,因为我在 freebsd 7.4(但服务器是四核)上没有看到任何延迟......但是在旧的(两个核心)和 freebsd 6.4 上,延迟是 14-30 秒。

标签: c++ memory system popen


【解决方案1】:

这只是关于如何处理您提出的解决方案的建议。对于您询问的两个具体操作:

  • touch: 可以通过打开和关闭要触摸的文件来达到类似的效果
    • 注意不要在open 上使用O_TRUNC 标志
  • ls:有点痛苦,因为你需要在 POSIX 系统上使用dirent.h,然后遍历结果
    • opendir
    • readdir
    • 完成后请务必致电closedir

如果您想将 systempopen 调用替换为使用 vfork 的等效调用,则需要小心。 vfork 调用使用起来有点棘手,因为如果孩子在调用后立即执行 exec 以外的任何操作,您就有可能破坏父级的内存状态。

替换为system

  • 创建一个帮助程序来执行参数中提供的字符串
    • 帮助程序可以在提供的参数上调用system,或者解析命令字符串并调用exec
  • 在您的 system 替换函数中,创建一个 arg 向量来调用帮助程序,并将您真正想要执行的程序字符串作为参数传递给该程序
  • 在你调用vfork后,你立即exec子里的助手程序
  • 父母等待孩子完成

在您的popen 替换中:

  • 创建一个辅助程序,接受stdoutstdin 文件描述符作为参数,以及要执行的命令字符串
    • 帮助程序会将传入的描述符复制到参数指示的01(或两者)
    • 帮助程序可以使用popen和父子之间的代理数据来执行字符串,或者在解析命令字符串后调用exec
  • 在您的popen 替换函数中,使用pipe 创建stdoutstdin 通信通道(根据第二个popen 函数参数)并创建一个arg 向量来调用帮助程序,传递在适当的文件描述符编号和命令字符串中作为参数
  • 调用vfork 后,您立即exec 子程序中的帮助程序
  • 你需要一个 pclose 替换来获取子进程

【讨论】:

  • vforkexec 的所有父线程都将挂起并等待for child to complete。我们必须使用execvevfork 之后立即继续父级以避免服务器hang。但它不能替代system 调用,因为我们必须只在被调用线程处等待。
  • @abrahab:您可以通过在助手的子进程中执行之前先让助手程序分叉来处理这个问题,然后让助手程序立即退出。要获得system 的阻塞语义,请使用pipe,并且system 替换的父级将在wait 完成后读取管道fd,当执行命令的孙子完成并退出时,它将自动关闭管道的写端。 popen 的类似技术
  • 可能值得注意的是,用于 system 的特定 exec 命令是众所周知的,并且与 vfork 和 fork 一样好用。 execl("/bin/sh", "sh", "-c", cmd, NULL);
  • @codetaku:好点。让我想想如何措辞,因为我将替换 system 表示需要替换所有内容(因此,不要调用 shell)。
【解决方案2】:
Another way is to use the "fork()" with "execvp()" in child process. as mentioned by @jxh

int pid = fork();

if( pid == 0)
{
// In child process
  // redirect stderr/stdinput/stdoutput
  // prepare the execution command
  //use the exec() family of functions as per specific requirement.
}
else
{
// In parent process
  // check for open pipes and close the Std Output/Input/Error pipes.
}

详细参考

https://www3.physnet.uni-hamburg.de/physnet/Tru64-Unix/HTML/APS33DTE/DOCU_004.HTM

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    相关资源
    最近更新 更多