每个进程都有一个非负整型表示唯一的进程ID。但是进程ID时可复用的,当一个进程终止后,其进程ID就成为复用的候选者。
1.1 系统专用进程- 0号进程。ID为0的通常为调度进程,常被称为交换进程。该进程是内核的一部分,并不执行任何磁盘上的程序,因此也被称为系统进程。
- 1号进程。ID为1的通常是init进程。该进程的程序文件在新版本中是/sbin/init。此进程负责在自举内核后启动一个UNIX系统。init通常读取与系统有关的初始化文件,并将系统引导到一个状态(如多用户)。init进程决不会终止。它是一个普通的用户进程(与交换进程不同),但是它以超级用户特权运行。
#include二、函数fork 1.1 创建新进程:pid_t getpid(void); //返回调用进程的进程ID pid_t getppid(void); //返回调用进程的父进程ID pid_t getuid(void); //返回调用进程的实际用户ID pid_t geteuid(void); //返回调用进程的有效用户ID pid_t getgid(void); //返回调用进程的实际组ID pid_t getegid(void); //返回调用进程的有效组ID
#includepid_t fork(void);
子进程返回0,父进程返回子进程ID;若出错返回-1.
- 将子进程ID返回给父进程的理由是:一个进程可以有多个子进程,且没有一个函数使一个进程可以获得其所有子进程的进程ID。
- 使子进程返回0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用getppid获得其父进程的进程ID。
注:写时复制(copy-on-write)。进程区域由父进程和子进程共享,而且内核将它们的访问权限改变为只读。若父进程和子进程中的一个试图修改这些区域,则内核只为修改区域的那块内存制作一个副本,通常是虚拟存储系统中的一“页”。
1.2 父子进程之间的文件共享fork的一个特性是父进程的所有打开文件描述符都被复制到子进程中。父进程和子进程每个相同的打开文件描述符共享同一个文件表项。
重要的是,父子进程共享同一个文件偏移量。如果父进程和子进程写同一描述符指向的文件,但又没有任何形式的同步,那么它们的输出就会相互混合。
fork失败的两个主要原因是:(1)系统中已经有了太多进程(2)该实际用户ID的进程总数超过了系统限制。
fork有以下两种用法:(1)父进程希望复制自己,使父进程和子进程执行不同的代码段。这在网络服务进程中是常见的。(2)一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec。
vfork函数用于创建一个新进程,该进程目的是exec一个新程序,如fork用法二。两者区别是:
(1)vfork并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec(或exit),于是也就是不会引用该地址空间。不过在子进程调用exec或exit之前,它在父进程的空间中运行。
(2)vfork保证子进程先运行,在它调用exec或exit后父进程才可能被调度运行(如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁)。
进程的8种终止方式。
5种正常终止:
(1)在main函数中执行return语句。等效于调用exit
(2)调用exit函数。ISO C定义,其操作包括调用各类终止程序,然后关闭所有标准I/O流等。因为ISO C并不处理文件描述符、多进程以及作业控制,所以这一定义对UNIX系统是不完整的
(3)调用_Exit或_exit函数。ISO C定义_Exit, 其目的是为进程提供一种无需运行终止处理程序或信号处理程序而终止的方法。对标准I/O流是否进行冲洗,取决于实现。在UNIX中,_Exit和exit是同义的,并不冲洗标准I/O流。_exit函数由exit调用
(4)进程的最后一个线程调用return。但是该线程的返回值不作为进程返回值,最后一个线程返回时,该进程以终止状态0返回
(5)进程的最后一个线程调用pthread_exit函数。十一章进行详细说明
3种异常终止:
(1)调用abort。它产生SIGABRT信号,这是信号终止的一种特例
(2)当进程接收到某些信号时。信号可由自身(如调用abort)、其他进程或内核产生
(3)最后一个线程对“取消(cancellation)”请求做出响应。十一、十二章详细说明
无论进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。对于上述任意一种情形,我们都希望进程能够通知其父进程它是如何终止的。
- 对于三个终止函数(exit、_exit和_Exit),将其退出状态(exit status)作为参数传送给函数。
- 对于异常终止。内核产生一个指示其异常终止原因的终止状态(termination status)。
在任意一种情况下,该终止进程的父进程都能用wait或waitpid函数取得其终止状态。
当一个进程终止时(正常或异常),内核就向其父进程发送SIGCHLD信号,父进程默认忽略该信号。
调用wait或waitpid的进程可能会发生什么:
- 如果所有子进程均在运行,则阻塞
- 如果一个子进程已终止,则获取其终止状态并立即返回
- 如果没有子进程,则立即出错返回
#includepid_t wait(int* statloc); pid_t waitpid(pid_t pid, int* statloc, int options);
成功,返回进程ID;出错则返回0或-1。两个函数的区别如下
- 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一选项,可使调用者不阻塞
- waitpid并不等待在其调用之后的第一个终止子进程,它有若干选项,可以控制它所等待的进程
这两个函数的参数是一个整型指针。若statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内。如果不关心终止状态,则可将该参数指定为空指针。
waitpid中有一些额外参数,用于等待一个特定进程。
(1)参数pid
pid == -1 : 等待任一子进程,与wait等效
pid > 0 :等待进程ID 与pid相等的子进程
pid == 0:等待组ID等于调用进程组ID的任一子进程
pid < -1 :等待组ID等于pid绝对值的任一子进程
(2)参数options:进一步控制waitpid的操作
此参数为0或者为以下常量按位或的结果
WNOHANG:非阻塞模式,若pid子进程不可用,则返回0
WCONTINUED:
WUNTARCED:
上面两个选项与支持作业相关
类似waitpid,但提供了更多的灵活性
#includeint waitid(idtype_t idtype, id_t id, siginfo_t* infop, int options);
成功返回0,出错返回-1。与waitpid不同,waitid使用两个单独参数表示要等待的子进程所属的类型。
(1)参数idtype
P_PID:等待特定进程
P_PGID:等待一特定进程组中的任一子进程
P_ALL:等待任一子进程
(2)参数options,为以下常量按位或的结果
WCONTINUED:等待一进程,以前曾被停止,此后又继续,但其状态尚未报告
WEXITED:等待已退出的进程
WNOHANG:如无可用的子进程退出状态,立即返回而非阻塞
WNOWAIT:不破坏子进程退出状态。该子进程退出状态仍可被wait等捕捉
WSTOPPED:等待一进程,已经停止但未报告状态
WCONTINUED, WEXITED, WSTOPPED必须在options中指定其一。
infop参数时指向siginfo结构的指针,包含造成子进程状态改变有关信号的详细信息。第十章详细讨论。
七、wait3和wait4允许内核返回由终止进程及其所有子进程使用的资源概况。
八、函数exec


