Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2381686
  • 博文数量: 298
  • 博客积分: 7876
  • 博客等级: 准将
  • 技术积分: 5500
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-23 13:39
文章存档

2013年(2)

2012年(142)

2011年(154)

分类: LINUX

2011-04-04 19:50:05

以下内容来自:

http://blogold.chinaunix.net/u1/59291/article.php?frmid=83308

 

一、进程ID

1

名称:

getpid

功能:

获得进程id.

头文件:

#include

函数原形:

pid_t getpid(void);

参数:

返回值:

进程id.

 

 

 

 

 

 

 

 

 

每个进程都有一个非负整数表示的唯一进程id。系统中有一些专用的进程该进程是内核的一部分,它并不执行任何磁盘上的程序。因此也被称为系统进程。

进程1通常是init进程,在自举过程完成时有内核调用。此进程负责在自举内核后启动一个UNIX系统。init通常读与系统有关的初始化文件(/ect/re*文件或/ect/inittab文件,以及/ect/init.d中的文件),并将系统引导到一个状态。但要注意init并不是一个系统进程,它是一个普通用户进程,但是它以超级用户特权运行。

 

2.

名称:

getppid

功能:

获得进程的父进程id

头文件:

#include

函数原形:

pid_t getppid(void);

参数:

返回值:

父进程id.

 

 

 

 

 

 

 

 

 

 

3.

名称:

getuid/geteuid

功能:

获得调用进程用户的实际用户id和有效用户id.

头文件:

#include

函数原形:

uid_t getuid(void);

uid_t geteuid(void)

参数:

返回值:

用户id.

 

 

 

 

 

 

 

 

 

 

 

4

名称:

getgid/getegid

功能:

获得调用进程用户的实际组id和有效组id.

头文件:

#include

函数原形:

gid_t getgid(void);

gid_t getegid(void);

参数:

返回值:

用户组id.

 

 

 

 

 

 

 

 

 

 

与一个进程相关联的用户id6个或更多,他们是:实际用户id          实际组id       有效用户id        有效组id        保存的设置用户id  保存的设置组id

实际用户id和实际组id标识我们究竟是谁。这两个字段在登陆时取自口令文件中的登陆项。通常,在一个登陆会话间这些值并不改变,但是超级用户进程又方法改变它们。

       有效用户id和有效组id以及附加组id决定了我们的文件访问权限。

       保存的设置用户id和保存的设置组id在执行一个程序是包含了有效用户id和有效组id的副本。

通常有效用户id等于实际用户id,有效组id等于实际组id。它们不同的情况通过发生在变更用户权限,但是不切换用户的情况下。

linux中有许多id,我们要注意这些id 的区别。getpid,getuid是获得当前进程和进程组的id,而getuid,geteuid,getgid,getegid是获取当前用户和用户组的id

 

下面的程序打印和进程id和用户id

/*8_1.c*/

#include

 

main()

{

printf(“pid:%d\n”,getpid());/*获得进程id*/

printf(“ppid:%d\n”,getppid());/*获得父进程id*/

printf(“uid:%d\n”,getuid());/*获得当前用户的实际用户id*/

printf(“euid:%d\n”,geteuid());/*获得当前用户的有效用户id*/

printf(“gid:%d\n”,getgid());/*获得当前用户的实际组id*/

printf(“egid:%d\”,getegid());/*获得当前用户的有效组id*/

}

 

 

二、创建进程

5

名称:

fork

功能:

创建一个进程

头文件:

#include

#include

函数原形:

pid_t fork(void);

参数:

返回值:

子进程返回0,父进程返回子进程id,出错返回1

 

 

 

 

 

 

 

 

 

 

fork创建的进程称为子进程,fork函数被调用一次,但返回两次。两次返回唯一区别是子进程返回的是0,父进程返回的是子进程的id.子进程是父进程的副本子进程获得父进程数据空间、堆和栈的副本。父、子进程并不共享这些存储空间,父、子进程只共享正文段。由于在fork之后经常跟着exec,所以现在很多实现并不执行一个父进程数据段、堆和栈的完全复制,它们采用一种叫做写时复制技术。

       fork有两种用法:

(1)    一个父进程希望复制自己,使父、子进程同时执行不同的代码段。

(2)    一个进程要执行一个不同的程序。这对shell是常见的情况。

下面是fork函数的一个例子。

/*8_2.c*/

include

#include

 

int main()

{

pid_t pid;

 

if((pid=fork())==0)

    printf(“I’am childmy id is %d\my father id is %d\n”,getpid(),getppid()”);

else

    printf(“I’am father, my id is %d\nmy child id is %d\n”,getpid(),pid);

}

 

下面运行结果:

#./8_2

I’am childmy id is 1859

my father id is 1858

I’am father, my id is 1858

my child id is 1859

 

6

名称:

vfork

功能:

创建一个进程

头文件:

#include

#include

函数原形:

pid_t vfork(void);

参数:

返回值:

进程id.

 

 

 

 

 

 

 

 

vforkfork一样都创建一个进程,但是它并不是将父进程的地址空间完全复制到子进程中,在子进程调用execexit之前,它在父进程的空间中运行。这要就提高了效率。

       vforkfork的另一个区别是:vfork保证子进程先运行,在它调度exexexit后父进程才可能被调度运行。

 

三、等待进程终止

7

名称:

wait/waitpid

功能:

等待一个进程的终止

头文件:

#include

#include

函数原形:

pid_t wait(int *statloc);

pid_t waitpid(pid_t pid,int *statloc,int options);

参数:

statloc 指向存放终止状态单元的指针

pid    options  控制wait的操作

返回值:

若成功返回进程id,若出错返回0

 

 

 

 

 

 

 

 

 

 

 

 

 

两个函数都是的功能都是获取子进程终止状态,但在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。

       如果一个之进程已经终止,并且是一个僵尸进程,则wait立即返回并取得该子进程的状态,否则wait使其调用者阻塞直到一个子进程终止。

 

waitpid并不等待在其调用之后的第一个终止进程,它有若干个选项,可以控制它所等待的进程。

       对于waitpid函数的参数pid的解释如下:

              pid==-1   等待任一子进程。

              pid>0      等待其进程与pid相等的子进程。

              pid<-1     等待其组id等于pid绝对值的任一子进程。

       options参数使我们能进一步控制waitpid的操作。此参数可以是0,或者是:

              WCONTINUED  用于作用控制

              WNOHANG          pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0

              WUNTRACED       用于作业控制。

 

对于僵尸进程的解释:

在一个进程调用了exit之后,该进程并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构。 
Linux进程的5种状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。

 

下面是wait的一个例子。

/*8_3.c*/

#include

#include

#include

#include

 

main()

{

pid_t pid;

pid_t cpid;

 

if((pid=fork())==0)

{

    printf(“I’m a child,my id is %d\n”,getpid());

    sleep(1);

    exit(1);

}

else

{

    printf(“I’m a father,my id is %d\n”,getpid());

    if((cpid=wait(NULL))!=-1)

        printf(“I catch a child is %d\n”,cpid);

}

}

 

运行结果是:

I’m child,my id is 16557

I’m father,my id is 16556

I catch a child is 16557

 

程序先打印子、父进程的id.然后子进程调用sleep函数,这时父进程阻塞,直到子进程调用exit终止退出,父进程获得子进程终止信息。

 

8

名称:

wait3/wait4

功能:

等待一个进程的终止

头文件:

#include

#include

#include

#include

函数原形:

pid_t wait3(int *stacloc,int options,struct rusage *rusage);

pid_t wait4(pid_t pid,int *statloc,int options,struct rusage *rusage);

参数:

 

返回值:

若成功返回进程id ,若出错返回-1

 

 

 

 

 

 

 

 

 

 

 

wait3,wait4的功能更强大,这与附加参数rusage有关。该函数要求内核返回由终止进程及其所有子进程使用的资源汇总。资源统计信息包括用户CPU时间总量,系统CPU时间总量,页面出错次数,接收到信号的次数等。

四、执行新程序

9

名称:

exec

功能:

执行一个新程序

头文件:

#include

函数原形:

int execl(const char *path,const char *arg,…);

int execlpconst char *file,const char *arg,…;

int execle(const char *path,const char *arg,…,char *const envp[]);

int execv(const char *fath,char *const argv[]);

int execvp(const char *file,char *const argv[]);

int execve(const char *file,char *const argv[],char *const envp[]);

参数:

path 路径名

file  文件名

arg  单独的命令参数,以NULL结束。

argv 指向命令参数列表

envp 指向环境字符串指针数组的指针

返回值:

若出错返回-1。若成功不返回值

      

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其main函数开始执行。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文,数据,堆和栈段。

       有六种不同的exec函数可供使用,它们常常被统称为exec函数。在这些函数中字母p表示该函数取filename作为参数,并且用PATH环境变量寻找可执行文件。字母l表示该函数去一个参数表,它与字符v互斥。v表示该函数去一个argv[]矢量。最后,字母e表示该函数取envp[]数组,而不使用当前环境。

       在执行exec前后实际用户ID和实际组ID保持不变,而有效ID是否改变则取决于所执行程序文件的设置用户ID位和设置组ID位是否设置。如果新程序的设置用户ID位已设置,则有效用户ID变成程序文件所以者的ID,否则有效用户ID不变。对组ID的处理方式与此相同。

 

/*8_4.c*/

#include

#include

#include

 

int main(int argc,char *argv[])

{

pid_t pid;

if((pid=fork())==0)

    execvp(argv[1],argv);

else

    waitpid(pid,NULL,0);

}

 

下面是运行结果:

#./8_4 ./main ll dd

./8_4

./main

ll

dd

程序先利用argv[1]调用./main函数,然后把argv传给main函数,把参数打印到屏幕上。要注意main函数必须和本程序在同一目录下。

 

五、更改ID

10

名称:

setuid/setgid

功能:

更改用户ID和组ID

头文件:

#include

#include

函数原形:

int setuid(uid_t uid);

int setgid(uid_t gid);

参数:

uid 用户ID

gid 用户组ID

返回值:

若成功返回进程0,若出错返回-1

(1)      

 

 

 

 

 

 

 

 

 

 

 

 若进程具有超级用户特权,则setuid函数将实际用户ID,有效用户ID,以及保存的设置-用户-ID设置为uid.

(2)       若进程没有超级用户特权,但是uid等于实际用户ID或保存的设置-用户-ID,则setuid只有效用户ID设置为uid。不改变实际用户ID和保存的设置-用户-ID

(3)       如果上面两个条件都不满足,则errno设置-用户-ID

 

11

名称:

setreuid/setregid

功能:

交换实际用户ID和有效用户ID.

头文件:

#include

函数原形:

int setreuid(uid_t ruid,uid_t euid);

int setregid(gid_t rgid,uid_t egid);

参数:

euid 有效用户id

ruid 实际用户id

egid 有效组id

rgid实际组id

返回值:

若成功返回进程0,若出错返回-1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

可以用setuid函数设置实际用户ID和有效用户ID。与此类似,可以用setgid函数设置实际组ID和有效ID

 

12.

名称:

seteuid/setegid

功能:

更改用户有效ID和有效组ID

头文件:

#include

函数原形:

int setuid(uid_t uid);

int setgid(gid_t gid);

参数:

uid 用户id

gid id

返回值:

若成功返回进程0,若出错返回-1

阅读(922) | 评论(0) | 转发(1) |
0

上一篇:(7)线程同步

下一篇:(2)进程关系

给主人留下些什么吧!~~