分类: LINUX
2009-08-22 13:07:57
PCB中包括进程的描述信息、控制信息以及资源信息、CPU现场等等。PCB反映一个进程的动态特性,它控制了各个进程之间的制约关系。
一般情况下,在系统的PCB结构中,都包括了下列信息:
1) 进程描述信息。包括进程名称和标识、创建进程用户的用户名和标识、进程之间的
层次关系。
2) 控制信息。包括了进程的状态信息优先级、程序地址、调度信息以及与其它进程的 通信状况。
进程在活动期间可以处于就绪状态、执行状态和阻塞状态。执行状态表示该进程占有处理机;就绪状态表示进程已经得到了除处理机以外所有的资源,等待处理机调度;阻塞状态是由于进程缺少某个必需的资源引起的,它等待其它进程释放资源再 继续运行。
3) 资源管理信息。包括存储器信息、使用的输入/输出设备信息、文件系统信息等等, 记录了系统占有的内存大小,共享内存段大小以及地址,输入/输出设备的设备号,设备缓冲区长度和地址。
4) CPU现场。在系统运行过程中.处理器时间被划分为时间片,在每个时间片中执行 不同的进程,所以进程的执行不是一次完成的。在进行进程状态转换时.必须保存进程CPU现场的状态,以便下一次该进程被分配到时间片时,可以继续执行。 进程PCB块是系统控制进程的唯一途径。通过对PCB的操作,系统为进程分配调度所需要的资源,获取地址信息并保存进程状态转换时的环境。进程结束时,系统通过释放PCB块,就可以释放进程所占有的资源。
int fork()
int pid;
if((pid=fork())==0){
/* child process. */
}else if (pid>0){
/* 父进程*/
}else {
fprintf(stderr,”fork process error \n”);
}
ANSI C说明了三个用于存储空间动态分配的函数。
(1) malloc。分配指定字节数的存储区。此存储区中的初始值不确定。
(2) calloc。为指定长度的对象,分配能容纳其指定个数的存储空间。该空间中的每一位
( b i t )都初始化为0。
(3) realloc。更改以前分配区的长度(增加或减少)。当增加长度时,可能需将以前分配区的
内容移到另一个足够大的区域,而新增区域内的初始值则不确定。
[格式:]
#include
void *malloc(size_t s i z e) ;
void *calloc(size_t n o b j, size_t s i z e) ;
void *realloc(void * p t r, size_t n e w s i z e) ;
三个函数返回:若成功则为非空指针,若出错则为N U L L
void free(void * p t r)
这三个分配函数所返回的指针一定是适当对齐的,使其可用于任何数据对象。例如,在一个特定的系统上,如果最苛刻的对齐要求是d o u b l e,则对齐必须在8的倍数的地址单元处,那么这三个函数返回的指针都应这样对齐。
! EXAMPLE:
# include
# include
# include
void main(void)
{
char * s;
register int t;
s=malloc(80);
if(!s){
printf(“memory request failed ..\n”);
exit(1);
}
gets(s);
for(t=strlen(s)-1;t>=0;t--) putchar (s[t]);
free(s);
}
环境字符串的形式是:
n a m e = v a l u e
U N I X内核并不关心这种字符串的意义,它们的解释完全取决于各个应用程序。例如,
s h e l l使用了大量的环境变量。其中某一些在登录时自动设置(如H O M E,U S E R等),有些则由用户设置。我们通常在一个s h e l l起动文件中设置环境变量以控制s h e l l的动作。例如,若设置了环境变量M A I L PAT H,则它告诉Bourne shell和K o r n S h e l l到哪里去查看邮件。
ANSI C定义了一个函数g e t e n v,可以用其取环境变量值,但是该标准又称环境的内容是由
实现定义的。
[格式:]
#include
char *getenv(const char * n a m e) ;
返回:指向与n a m e关联的v a l u e的指针,若未找到则为N U L L
注意,此函数返回一个指针,它指向n a m e = v a l u e字符串中的v a l u e。我们应当使用g e t e n v从环境中取一个环境变量的值,而不是直接存取e n v i r o n。
! EXAMPLE:
short init_msgq()
{
char pathfil[40];
strcpy(pathfil,(char*)getenv("WORKDIR"));
strcat(pathfil,FILE_NAME);
return 0;
}
[格式:]
#include
int putenv(const char * s t r) ;
int setenv(const char * n a m e, const char * v a l u e, int re w r i t e) ;
两个函数返回:若成功则为0,若出错则为非0
void unsetenv(const char * n a m e) ;
这三个函数的操作是:
• putenv取形式为n a m e = v a l u e的字符串,将其放到环境表中。如果n a m e已经存在,则先删除其原来的定义。
• setenv将n a m e设置为v a l u e。如果在环境中n a m e已经存在,那么( a )若re w r i t e非0,则首先删除其现存的定义;( b )若re w r i t e为0,则不删除其现存定义(n a m e不设置为新的v a l u e,而且也不出错)。
• unsetenv删除n a m e的定义。即使不存在这种定义也不算出错。
这些函数在修改环境表时操作:
环境表(指向实际n a m e = v a l u e字符串的指针数组)和环境字符串典型地存放在进程存储空间的顶部(栈之上)。
删除一个字符串很简单——只要先找到该指针,然后将所有后续指针都向下移一个位置。但是增加一个字符串或修改一个现存的字符串就比较困难。栈以上的空间因为已处于进程存储空间的顶部,所以无法扩充,即无法向上扩充,也无法向下扩充。
(1) 如果修改一个现存的n a m e:
(a) 如果新v a l u e的长度少于或等于现存v a l u e的长度,则只要在原字符串所用空间中写入新字符串。
(b) 如果新v a l u e的长度大于原长度,则必须调用m a l l o c为新字符串分配空间,然后将新字符写入该空间中,然后使环境表中针对n a m e的指针指向新分配区。
(2) 如果要增加一个新的n a m e,则操作就更加复杂。首先,调用m a l l o c为n a m e = v a l u e分配空间,然后将该字符串写入此空间中。
(a) 然后,如果这是第一次增加一个新n a m e,则必须调用m a l l o c为新的指针表分配空间。将原来的环境表复制到新分配区,并将指向新n a m e = v a l u e的指针存在该指针表的表尾,然后又将一个空指针存在其后。最后使e n v i r o n指向新指针表.如果原来的环境表位于栈顶之上(这是一种常见情况),那么必须将此表移至堆中。但是,此表中的大多数指针仍指向栈顶之上的各n a m e = v a l u e字符串。
(b) 如果这不是第一次增加一个新n a m e,则可知以前已调用m a l l o c在堆中为环境表分配
了空间,所以只要调用r e a l l o c,以分配比原空间多存放一个指针的空间。然后将该
指向新n a m e = v a l u e字符串的指针存放在该表表尾,后面跟着一个空指针。