用 fork()+exec() 运行子进程
诀窍是在子进程中调用
exec() 函数,这样原来的父进程就能继续运行了。我们一步一步来看。
- 复制进程
第一步用
fork() 系统调用复制当前进程。
进程需要以某种方式区分自己是父进程还是子进程,为此 fork() 函数向子进程返回 0,向父进程返回非零值。
如果是子进程,就调用 exec()
这一刻,你有两个完全相同的进程在运行,它们使用相同的代码,但子进程(从
fork() 接收到 0 的那个)现在需要调用 exec() 运行程序替换自己:
现在你有两个独立的进程:子进程在运行 rssgossip.py 脚本,而原来的父进程可以继续做其他事,完全不受干扰。
代码冰箱贴
下面就来修改 newshound 程序。代码需要在独立进程中为每条 RSS 源运行 rssgossip.py 脚本。我们缩减了代码,你只需关注主循环即可。记得检查错误,千万别把父进程和子进程搞混了!
叉子函数
你可以像这样调用 fork() :pid_t pid = fork();
fork() 会返回一个整型值:为子进程返回 0,为父进程返回一个正数。父进程将接收到子进程的进程标识符。什么是 pid_t ?不同操作系统用不同的整数类型保存进程 ID,有的用 short ,有的用 int ,操作系统使用哪种类型,pid_t 就设为哪个。
代码冰箱贴解答
下面就来修改 newshound 程序。代码需要在独立进程中为每条 RSS 源运行 rssgossip.py 脚本。我们缩减了代码,你只需关注主循环即可。记得检查错误,千万别把父进程和子进程搞混了!
试驾
现在编译并运行代码,将看到:
通过克隆自己,然后在独立进程中运行 Python 脚本,newshound 成功地为每个 RSS 源运行了独立的进程,而且最妙的是这些进程将同时运行。
这要比逐条读取新闻源快多了。通过学习用 fork() 和 exec() 创建并运行独立进程,不但能更好地利用现有软件,而且还能提高程序的性能。这里没有蠢问题问:system() 能在独立进程中运行程序吗?答:可以,但使用 system() 使你没办法控制程序的运行方式。问:克隆进程岂不是很慢?我的意思是在用 exec() 替换子进程前我们还要等 fork() 复制完整个进程。答:为了让 fork 进程变快,操作系统使用了很多技巧。比如操作系统不会真的复制父进程的数据,而是让父子进程共享数据。问:这样一来,如果子进程修改了存储器中的数据,岂不是会把事情搞砸?答:不会,如果操作系统发现子进程要修改存储器,就会为它复制一份。问:这技术听起来真酷,有名字吗?答:有,叫“写时复制”(copy-on-write)。问:pid_t 就是 int 吗?答:这取决于平台,你唯一知道的就是它是整型。问:我在 int 里保存 fork() 调用的结果,程序还是能运行。答:最好还是用 pid_t 来保存进程 ID,否则当把代码拿到其他机器上编译时可能会出错。问:为什么 Windows 不支持 fork() 系统调用?答:Windows 管理进程的方式和其他操作系统完全不同,那些用来提高 fork() 效率的方法在 Windows 上很难实现,这可能就是为什么 Windows 没有内置的 fork() 。问:但 Cygwin 能让我在 Windows 中调用 fork() ,对吗?答:是的,为了让 Windows 的进程看起来和 Linux、Unix 和 Mac 的一样,写 Cygwin 的专家做了很多工作。但由于他们还是需要依靠 Windows 来创建底层进程,所以 Cygwin 上的 fork() 要比其他平台上的 fork() 慢一些。问:如果我想让代码能在 Windows 上运行,有其他替代品吗?答:嗯,有一个名叫 CreateProcess() 的函数,它是一个加强版的 system() 。如果你想了解更多信息,可以到 搜索 CreateProcess。 http://msdn.microsoft.com 问:多个新闻源的输出为什么不会混在一起?答:操作系统会确保每个字符串都完整地打印出来。
要点
系统调用是内核中的函数。
exec() 函数比 system() 提供了更多控制权。
exec() 函数替换当前进程。
fork() 函数复制当前进程。
系统调用在失败时通常返回-1。
系统调用失败以后会把 errno 变量设为错误码。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论