进程及进程控制(一)

一 基本概念:
1.进程标识符

进程标识符(ID)是一个非负整数,是唯一的,但是可以重用。
系统专用进程:
交换进程:ID为0,是内核的一部分,也被成为系统进程。
init进程:ID为1,在自举过程结束时由内核,调用,通常读与系统有关的初始化文件(如/etc/init.d中的文件),并将系统引导到一个状态。init进程不会终止,是一个普通用户进程(第一个运行的用户进程),但是以超级用户特权运行。init进程成为所有孤儿进程的父进程

2. 进程关系:
每个进程除了有一个进程ID外,还属于一个进程组。
进程组是一个或多个进程的集合,可以接受来自同一终端的各种信号。每个进程组都可以有一个组长进程,进程组ID等于其进程ID。
组长进程可以创建一个进程组、创建组中的进程,然后终止。只要在某个进程组中有一个进程存在,则该进程组就存在,与组长进程是否终止无关。进程组的生存期:从进程组创建开始到其中最后一个进程离开为止。
会话:是一个或多个进程组的集合。一个会话可以有一个终端,一个会话中的几个进程组可以分成一个前台进程组以及一个或者几个后台进程组。

3.相关函数:
pid_t getpid(void):返回调用进程的进程ID。
pid_t getppid(void):返回调用进程的父进程ID。
uid_t getuid(void):返回调用进程的实际用户ID。
uid_t geteuid(void):返回调用进程的有效用户ID。
gid_t getgid(void):返回进程的实际组ID。
gid_t getegid(void):返回进程的有效组ID。

二 具体应用:

(一)创建进程:

(1)fork函数:

函数原型:
pid_t fork(void);//返回值:子进程返回0,父进程返回子进程ID;出错返回-1。
fork之后是父进程先执行还是子进程先执行是不确定的,取决于内核所使用的调度算法。

*子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本,如:子进程获得父进程数据空间、堆和栈的副本。父子进程共享正文段(CPU执行的机器指令部分)。
由于fork之后经常跟随exec,所以现在很多实现并不执行父进程数据段、堆和栈的完全复制。而是采用写时复制(Copy-On-Write,COW)技术:这些区域由父子进程共享,而且内核将它们的访问权限改变为只读,如果父子进程中的任何一个试图修改这些区域,则内核只为修改区域的那块内存制作一个副本。

文件共享:
fork之后,父进程的所有打开的文件描述符都被复制到子进程中。父子进程的每个相同的打开描述符共享一个文件表项。
在fork之后处理文件描述符的两种常见情况:
*父进程等待子进程完成。
*父、子进程执行不同的程序段。父、子进程各自关闭不需使用的文件描述符,这样就不会干扰到对方使用的文件描述符。网络服务进程中常用。

(2)vfork函数:
原型:pid_t vfork(void)
vfork用于创建一个进程,而该新进程的目的是exec一个新程序(shell)。
vfork与fork的区别:
*vfork不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec或exit,于是也就不会存访该地址空间。在子进程调用exec或exit之前,它在父进程的地址空间内运行。在某些UNIX的页式虚拟存储器的实现中提高了效率。
*vfork保证子进程先运行,在它调用exec或exit之后,父进程才可能被调度运行。

(二)进程终止:

(1)进程正常终止的5种情况:
*在main函数中执行return语句。
*调用exit函数。
*调用_exit或_Exit函数。
*最后一个线程从其启动例程中返回。
*最后一个线程调用pthread_exit。

*exit、_exit和_Exit区别:
~_exit和_Exit直接进入内核,exit则优先执行一些清理操作(包括调用执行各终止处理程序(终止程序在调用atexit函数时登记),关闭所有标准I/O流)。
~exit和_Exit是ISO C说明的(#include<stdlib.h>),exit是POSIX说明的(#include<unistd.h>)。

atexit函数:(#include<stdlib.h>)
*原型:int atexit(void (*func)(void))
*ISO C规定,一个进程可以登记多达32个函数。这些函数由exit自动调用(包括return 0),这些函数称为终止处理程序,由atexit来登记。
*exit调用这些函数的顺序与它们登记的时候的顺序相反。同一函数登记多次,则也会被调用多次。


(2)异常终止的3种情况:
*调用abort。它产生SIGABRT信号。
*当进程受到某些信号。信号可有进程自己、内核或其他进程产生。
*最后一个线程对“取消”请求作出响应。

(3)僵死进程与孤儿进程:
*僵死进程:一个进程终止,但其父进程尚未对其进行善后处理(获取终止子进程的有关信息,释放它仍占用的资源),ps显示状态为Z
*孤儿进程:父进程在子进程之前终止,子进程变为孤儿进程。孤儿进程的父进程都将改变为init进程。init进程被编写成无论何时只要有一个子进程终止,init就会调用一个wait函数来取得其终止状态。这就防止僵死进程的产生。

(4)无论进程如何终止,最后都会执行内核中的同一段代码:为相应进程关闭所有打开描述符,释放它使用的存储器等。

(三) wait和waitpid函数:
(1)概述:
无论进程正常或异常终止,内核都向其父进程发送SIGCHLD信号。父进程可以忽略该信号(默认),或者提供一个该信号发生时即被调用执行的函数(信号处理程序)。

*函数原型:
pid_t wait(int *status)
pid_t waitpid(pid_t pid,int *status,int options)
int waitid(idtype_t idtype,id_t id,siginfo_t *infop,int options)//与waitpid类型,提供更多灵活性.
pid_t wait3(int *status,int options,struct rusage *rusage)
pid_t wait4(pid_t pid,int *status,int options,struct rusage *rusage)//wait3和wait4比wait和waitpid提供功能多一个,可以返回由终止进程及其所有子进程使用的资源汇总。

(2)wait与waitpid的区别:
*waitpid提供了一个非阻塞版的wait。在一个子进程终止前,wait使调用者阻塞;而waitpid有一个选项,可使调用者不阻塞。
*waitpid可等待一个特定进程;wait是只要有一个子进程终止就返回。
*waitpid支持作业控制。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值