Linux的进程操作(创建进程)

在Linux中,创建一个新进程的唯一方法是由某个已存在的进程调用 fork 或 vfork 函数,被创建的新进程称为子进程(child process),已存在的进程称为父进程(father process)。

1. fork 函数基础

fork 函数实质是一个系统调用,作用是创建一个新的进程,当一个进程调用它,完成后就出现两个几乎一模一样的进程, 其中由 fork 创建的新进程被称为子进程,原来的进程称为父进程。子进程是父进程的一个拷贝,即子进程从父进程得到了数据段和堆栈段的拷贝,这些需要分配新的内存;对于只读的代码段,通常使用共享内存的方式访问。

用户通常在有如下需求的时候使用 fork 函数:

  • 一个进程希望复制自身,使得父子进程能同时执行不同段的代码,通常来说这种应用会涉及网络服务:父进程等待远端的一个请求或者应答,当收到这个请求或者应答的时候调用 fork 创建一个子进程来完成处理,而自己继续等待远端的请求或者应答。
  • 进程想执行另外一个程序, 例如在 Shell 中调用用户所生成的应用程序。

fork 函数的标准调用格式:

#include <unistd.h>
pid_t fork(void);

fork 函数没有参数,被调用一次,但返回两次:

  • 对于父进程而言:函数的返回值是子进程的进程标识符,因为一个进程的子进程可以多于一个,所以没有一个函数使一个进程可以获得其所有子进程的进程标识符,必须通过这种方式来收集。
  • 对于子进程而言:函数的返回值是0,一个进程只有一个父进程,所以子进程总是可以调用 getppid 获得其父进程的进程标识符,所以在这里不需要返回父进程的进程标识符。
  • 如果出错:返回值为“-1”。

可以通过 fork 函数的返回值来分辨父进程和子进程。

2. 子进程和父进程共享的数据空间

当 fork 函数返回后,子进程和父进程都从调用 fork 函数的下一条语句开始执行,但是父进程或子进程哪个先执行是随机的,取决于具体的调度算法,如果需要确定让其中一个先运行,可以使用 sleep 等函数让其中一个“休眠”一段时间,但是这个时间长度是不确定的。

通常来说,fork 所创建的子进程将会从父进程中拷贝父进程的数据空间、堆和堆栈,并且和父进程一起共享正文段,子进程所拷贝的仅仅是一个副本,和父进程的相应部分是完全独立的。

3. 子进程和父进程共享的文件

调用 fork 函数之后子进程会复制父进程的相应内存空间,父进程中所有打开的文件描述符也会被复制到子进程中,此时父进程和子进程的每个打开的文件描述符会共享同一个文件表项。

父进程和子进程共享文件的示意图。

在这里插入图片描述
fork 所创建的子进程和父进程共享同一个文件的偏移量,此时如果父进程和子进程同时对同一个文件进行写操作且没有任何形式的同步操作,会出现写文件的混乱。

4. 创建多个子进程

在 Linux 中可以使用 fork 函数创建多个子进程,以下为一段使用 while 循环调用 fork 函数无限制创建子进程的代码。

#include <unistd.h>
int main(int agrc,char *argv[])
{
    while(1)
    {
        fork();
    }
}

如果运行以上代码对应的可执行文件,由于无限制的创建进程导致硬件资源被分配光,Linux 会很快进入“死机状态”。

发布了71 篇原创文章 · 获赞 131 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43239560/article/details/102647995