Linux多进程--创建进程(fork/exit)

创建进程函数fork()

函数原型:pid_t fork(void);
头文件:#include 中
输入参数:无输入参数。
返回值:pid_t 	pid_t是一个宏定义,其实质是int被定义在#include 
	若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID,否则,出错返回-1.

函数说明:

fork通过复制当前进程的方式来创建一个新的进程,新产生的进程被称之为当前进程的子进程,当前进程称之为父进程。
子进程和父进程运行在单独的内存空间中,相互之间不共享任何空间,但在使用fork函数来创建进程时,子进程将获得父进程的数据空间,文件映射,堆栈等资源的副本,子进程拥有独立的地址空间,在不同的UNIX系统下,我们无法确定fork之后是子进程先运行还是父进程先运行。这依赖于系统的实现,所以在移植代码的时候我们不应该对此作出任何假设。

为什么fork会返回两次?

由于在复制时,复制了父进程的堆栈段,所以两个进程都停留在fork函数中,等待返回,因此fork函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回,这两次的返回值时不一样的。调用fork之后,数据堆栈都有两份,代码仍然只有一份,但是这个代码段称为两个进程的共享代码段,都从fork函数中返回。

子进程与父进程之间的关系

  1. 子进程拥有自己独立的进程ID,该进程ID不包含在任何已经存在的进程组当中。
  2. 子进程的父进程ID与父进程自己本身的ID保持一致。
  3. 子进程不继承父进程使用函数mlock和mlockall创建的内存锁。
  4. 在子进程创建时,进程时间和系统资源使用情况将会被重置
  5. 子进程在创建时子进程的信号集被初始化为空。
  6. 子进程不继承任何父进程对信号量的调整与修改操作。
  7. 子进程继承父进程的环境,堆栈,共享内存,打开文件的文件描述符,执行时的关闭标志,信号的控制设定,进程组号,工作目录,资源限制,控制终端。
  8. 子进程不继承父进程的异步输入输出。拥有自己独立的目录流的拷贝

返回错误类型

根据上述描述,当fork函数的返回值小于零时,表示创建进程失败,其具体的错误类型如下:

  1. EAGAIN : 从字面意思来理解是提示重试一次,常发生在应用程序进行一些非阻塞操作时。当fork函数返回这个错误时,表示当前用户使用的进程数量已经达到最大。
  2. ENOMEM:表示当前没有可分配的足够的内存空间用于创建进程。
  3. ENOSYS: fork函数不支持在当前平台上使用(比如:没有内存管理单元的应用程序)

退出进程函数exit()

函数原型:void exit(int status);
头文件:#include 
输入参数:
	status:当函数执行返回时,其值将会与0377进行与运算,返回给父进程。
返回值:无返回值

函数说明:

exit函数使用一个不被保护的全局变量实现进程的销毁,所以该函数并不是一个线程安全的函数。
exit函数退出以后,退出状态必须传输到父进程,这里有三种状态:

  1. 如果父进程有设置为SA_NOCLDWAIT状态,或父进程忽略信号SIGCHLD,子进程的exit状态将会被父进程丢弃。
  2. 如果父进程正在等待子进程结束,子进程的exit状态将会被传输到父进程。
  3. 如果父进程没有表明不关心子进程是否销毁,也没有等待子进程结束,那么子进程将会“僵死”,即变成僵尸进程。
    在第一种和第二种情况下,调用exit函数都将会导致进程立即结束。

如果父进程注册了来自子进程的信号SIGCHLD处理函数,则子进程将会发送该信号给父进程。需要注意的是,如果同时父进程设置了SA_NOCLDWAIT,则SIGCHLD信号的发送状态未知。

如果一个进程的结束导致一个进程组被孤立,那么如果该进程组中的任何进程的终止,将向该进程组中的每个进程首先发送一个SIGHUP信号然后发送一个SIGCONT信号。

在调用exit函数表示线程退出时,常使用EXIT_FAILURE字段表示进程的非正常退出,使用EXIT_SUCCESS表示进程正常退出。

你可能感兴趣的:(Linux)