分类: LINUX
2009-07-02 00:05:47
感觉关于linux系统基础方面的知识越来越模糊。好些东西知道大概是怎么回事。但是要说就说不清楚了。现在再整理一下。
一、进程标识
1) 什么是进程ID
每个进程都会有一个唯一非负整数的ID,就称为进程ID,因为其具有唯一性,常用来做其它标识符的部分以保证唯一性。
2) 特殊的进程ID
l 0 调度进程ID,也称为交换进程,它是内核的一部分。也被称为系统进程
l 1 inid进程,在自举过程结束时由内核调用;i n i t通常读与系统有关的初始化文件( / e t c / r c*文件),并将系统引导到一个状态(例如多用户),
l 2 精灵进程( pagedaemon)。此进程负责支持虚存系统的请页操作。与交换进程一样,页精灵进程也是内核进程。
3) 相关函数
#include
#include
pid_t getpid(void); 返回:调用进程的进程I D
pid_t getppid(void); 返回:调用进程的父进程I D
uid_t getuid(void); 返回:调用进程的实际用户I D
uid_t geteuid(void); 返回:调用进程的有效用户I D
gid_t getgid(void); 返回:调用进程的实际组I D
gid_t getegid(void); 返回:调用进程的有效组I D
l 与一个进程相关联的I D有六个或更多,如下图
l
实际用户I D和实际组I D标识我们究竟是谁。这两个字段在登录时取自口令文件中的登录项。通常,在一个登录会话期间这些值并不改变,但是超级用户进程有方法改变它们.l 有效用户I D,有效组I D以及添加组I D决定了我们的文件访问权
l 保存的设置-用户- I D和设置-组- I D在执行一个程序时包含了有效用户I D和有效组I D的副本
二、fork函数
fork是linux内核创建一个新进程的唯一方法,由fork创建的新进程称为子进程。。该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程I D
1) 为什么fork要返回两次
l fork是复制,包括了2个内核页面放进程描述符和其他资源,以及指向核外虚存页面的指针,fork后父子进程内容完全一样,所以需要不同的返回值来区分。当然,现在的fork里还有很多参数,用来控制页拷贝来提高效率。
l fork将子进程I D返回给父进程的理由是:因为一个进程的子进程可以多于一个,所以没有一个函数使一个进程可以获得其所有子进程的进程I D。
l fork使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用g e t p p i d以获得其父进程的进程I D (进程ID 0总是由交换进程使用,所以一个子进程的进程I D不可能为0 )
2) 子进程会复制和继承父进程哪些数据和资源
l 子进程是父进程的复制品。例如,子进程获得父进程数据空间、堆和栈的复制品。注意,这是子进程所拥有的拷贝。父、子进程并不共享这些存储空间部分。如果正文段是只读的,则父、子进程共享正文段, 现在很多的实现并不做一个父进程数据段和堆的完全拷贝,因为在f o r k之后经常跟随着e x e c。作为替代,使用了在写时复制( C o p y - O n - Write, COW)的技术。
l f o r k时由父进程打开的描述符都被复制到子进程中
l 其它继承的还有实际用户I D、实际组I D、有效用户I D、有效组I D。添加组I D。进程组I D。对话期I D。控制终端。设置-用户- I D标志和设置-组- I D标志
l 信号屏蔽和排列、环境、连接的共享存储段、资源限制
3) 什么情况下会fork失败
l 系统中已经有了太多的进程(通常意味着某个方面出了问题)
l 该实际用户I D的进程总数超过了系统限制。C H I L D _ M A X规定了每个实际用户I D在任一时刻可具有的最大进程数。
三、exit函数
1) 进程有三种正常终止法及两种异常终止法
A. 正常终止:
l 在m a i n函数内执行r e t u r n语句。这等效于调用e x i t。
l 调用e x i t函数。此函数由ANSI C定义,其操作包括调用各终止处理程序(终止处理程序在调用a t e x i t函数时登录),然后关闭所有标准I / O流等。因为ANSI C并不处理文件描述符、多进程(父、子进程)以及作业控制,所以这一定义对U N I X系统而言是不完整的。
l 调用_ e x i t系统调用函数。此函数由e x i t调用,它处理U N I X特定的细节。
A. 异常终止:
l 调用a b o r t。它产生S I G A B RT信号,所以是下一种异常终止的一种特例。
l 当进程接收到某个信号时。进程本身(例如调用a b o r t函数)、其他进程和内核都能产生传送到某一进程的信号。例如,进程越出其地址空间访问存储单元,或者除以0,内核就会为该进程产生相应的信号。
B. 不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等等
2) 什么是坐僵死进程
l 一个已经终止、但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息、释放它仍占用的资源)的进程被称为僵死进程( z o m b i e)
四、Wait和waitpid
前面讲了进程各种终止的情况,而且进程终止是一个异步事件,那么作为一个父进程如何获取子进程的终止状态呢?在linux系统中。当一个进程正常或者异常终止时,都会发送一个SIGCHLD信号,父进程可以忽略该信号,或者提供一个该信号发生时即被调用执行的函数(信号处理程序),能够捕捉此信号的函数有: wait 和waitpid等。下面先简单的介绍这两个函数
1) 函数原型
#include
#include
pid_t wait(int*statloc) ;
pid_t waitpid(pid_t pid,int *statloc,int options) ;
两个函数返回:若成功则为进程I D,若出错则为-1
2) 调用wait和waitpid的进程可能会怎么样?
l 阻塞(如果其所有子进程都还在运行)。
l 带子进程的终止状态立即返回(如果一个子进程已终止,正等待父进程存取其终止状态)。
l 出错立即返回(如果它没有任何子进程)。
3) wait和waitpid有什么区别
l 在一个子进程终止前, wait 使其调用者阻塞,而waitpid 有一选择项,可使调用者不阻塞。
l waitpid并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的进程。
4) 怎么检查子进程返回的状态
这两个函数都有一个参 int *statloc,如果*statloc不为空。则子进程的返回状态就保存在它所指向的单元内,那么要怎么才能检查出这个状态呢?已经使用以下几个宏来检查(当你不关心子进程的终止状态时,可把*statloc置为了NULL)
l WIFEXITED(status),若为正常终止子进程返回的状态,则为真。对于这种情况可执行WIFEXITED(status),取子进程传送给exit或_exit参数的低8位
l WIFSIGNALED(status),若为异常终止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WTERMSIG(status)取使子进程终止的信号编号。
l WIFSTOPPED(status),若为当前暂停子进程的返回的状态,则为真。对于这种情况,可执行WSTOPSIG(status)取使子进程暂停的信号编号
(未完)