多进程编程:fork()函数

       现实世界中,人们可以一边听音乐,一边阅读,一边吃零食等等;在计算机编程中,可以用多进程或多线程实现这种多任务,这样,人们就能够“同时”运行很多程序,以满足各种需求。

       从定义上来说,进程间是独立的,拥有各自独立的运行资源,如存储空间和数据等,而线程附属于进程,共享创建它的进程的部分资源。这样一来,一般认为线程消耗的资源比进程少。然而实际上的实现由操作系统开发者决定,综合考虑进程和线程的优缺点,权衡出一种合适的实现,例如Linux中的实现是所谓的“轻量级进程”,介于进程和线程之间。

      进入正题。在Unix/Linux中,创建进程的函数是fork(),创建线程可以使用pthread库。fork()函数具有一个很新奇的特性,即“一次调用,两次返回”。乍看之下可能觉得很奇怪,只调用一次,为什么会返回两次呢?其实联想到fork()的功能就可以猜到几分了。fork()函数用于创建子进程,这个子进程会复制父进程的地址空间,准备作为一个单独的进程运行。注意,这时还仅仅是准备。为了效率,Linux采用“写时复制”技术,即在父子进程改动堆栈段等之前,子进程虽然拥有独立的地址空间,但并不会为其分配物理地址空间。直到必要之时,父子进程分道扬镳,子进程才会自立门户,拥有独立的运行资源。

        fork()返回两次的奥秘在于,子进程复制了父进程的地址空间包括堆栈段,并共享父进程的代码段。复制完成后,由于栈相同,父子进程都运行在fork()函数内,对于父进程,fork()函数返回子进程的pid,子进程的fork()返回0。这类似于链表,父进程“指向”子进程,子进程指向NULL。如果因此,可以通过判断fork()的返回值来知道目前运行的是父进程还是子进程以执行不同的操作:

if ( (pid = fork()) == 0 ) //当前运行的是子进程
{
      do_sth_in_childprocess();
} 


       fork()后父子进程的代码段始终是相同的,若希望创建的子进程运行不同的程序,可以调用exec()函数,将某个程序的代码装载至进程。实际上并不存在exec()函数,它是一簇函数,包含6个

#include <unistd.h>
 
extern char **environ;
 
int execl(const char *path, const char *arg, ...);
 
int execlp(const char *file, const char *arg, ...);
 
int execle(const char *path, const char *arg, ..., char * const envp[]);
 
int execv(const char *path, char *const argv[]);
 
int execvp(const char *file, char *const argv[]);
 
int execve(const char *path, char *const argv[], char *const envp[]);


       exec是它们的公共前缀。其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。如果一个程序想执行另一个程序,就可以先fork()再exec(),这在Linux中十分普遍,例如shell执行用户输入的命令。之前说了,fork()采用写时复制技术,就是因为在很多情况下,fork()之后会紧接着执行exec(),运行的是另一个不同的程序,没有必要复制父进程的数据和堆栈等。

       现在来看看fork()的实现。在操作系统的函数调用层次中,最内层的是内核函数,用来实现内核功能,通常运行于内核态,不受用户的控制,甚至根本就不会暴露给用户。内核实现者会提供一套接口,就是所谓的API,来让用户调用操作系统的功能,而语言库会对API再做封装,就是库函数。我们通常使用的函数都是这一层次的函数,fork()函数也是。fork()库函数会调用操作系统API:sys_fork()函数,sys_fork()函数会再调用内核函数do_fork()来完成工作。很多关于创建进程的函数都是通过调用do_fork()来完成的。do_fork()还会调用一个辅助函数copy_process()。具体的实现可以在网上搜索相关资料或源码查看,在此不详述了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值