进程的基本属性:进程ID、父进程ID、进程组ID、会话和控制终端
摘要:本文主要介绍进程的基本属性,基本属性包含:进程ID、父进程ID、进程组ID、会话和控制终端.
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
函数说明:
每一个进程都有一个非负整型表示的唯一进程ID(PID).好比方我们的身份证一样,每一个人的身份证号是唯一的.由于进程ID标示符总是唯一的,常将其用来做其它标示符的一部分以保证其唯一性。进程ID(PID)是无法在用户层改动的.
在Linux系统中,PID为0 的进程一般是调度进程。经常被称为交换进程,也是第一个系统进程.第一个用户进程是init进程。其PID为1.
在应用编程中。调用getpid()函数能够获得当前进程的PID,此函数没有參数,假设运行成功返回当前进程的PID。失败返回-1。出错原因存储于errno.
样例1:打印自己的进程ID(PID).
#include <sys/types.h>
#include <unistd.h>
pid_t getppid(void);
函数说明:
不论什么进程(除init进程)都是由还有一个进程创建。该进程称为被创建进程的父进程。被创建的进程称为子进程。父进程ID无法在用户层改动.父进程的进程ID即为子进程的父进程ID(PPID).
用户能够通过调用getppid()函数来获得当前进程的父进程ID(PPID).此函数没有參数,假设运行成功返回当前进程的父进程ID(PPID)。失败返回-1,出错原因存储于errno.
样例1:打印自己的父进程PPID.
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);
pid_t getpgid(pid_t pid);
pid_t getpgrp(void); /* POSIX.1 version */
pid_t getpgrp(pid_t pid); /* BSD version */
int setpgrp(void); /* System V version */
int setpgrp(pid_t pid, pid_t pgid); /* BSD version */
函数说明:
在Linux系统中。每一个用户都实用户ID(UID)和用户组ID(GUID).相同,进程也拥有自己的进程ID(PID)和进程组ID(PGID). 进程组是一个或多个进程的集合;他们与同一作业相关联.每一个进程组都有唯一的进程组ID(PGID),进程组ID(PGID)能够在用户层改动.比方。将某个进程加入到还有一个进程组,就是使用setpgid()函数改动其进程组ID.
用户能够通过调用getpgid()函数来获得当前进程的进程组ID(PGID).若此參数为0表示获取当前进程的进程组ID,假设运行成功返回当前进程的进程组ID(PGID)。失败返回-1。出错原因存储于errno. 建议使用POSIX.1规定中的无參数getprgp()函数替代getpgid(pid)函数.
进程组ID(PGID)也能够通过函数getpgrp()获得.通过fork()函数产生的子进程会继承它的父进程的进程组ID(PGID).
每一个进程组都能够有一个组长进程,组长进程的进程组ID等于其进程ID.但组长进程能够先退出。即仅仅要在某个进程组中有一个进程存在,则该进程组就存在,与其组长进程是否存在无关.进程组的最后进程能够退出或转移到其它组.
能够将某个进程增加到某个进程组中,调用系统函数setpgid().其第一个參数为欲改动进程组ID(PGID)的进程ID(PID),第二參数为新的进程组ID(PGID),假设这两个參数相等,则由pid指定的进程变为该进程组组长。假设pid为0,则使用调用者的进程ID(即改动当前进程的进程组ID(PGID为指定的pgid));假设pgid是0,则由pid指定的进程ID(PID)。用做进程组ID(PGID)(即:pid所指进程作为进程组的组长进程).
一个进程仅仅能为自己或子进程设置进程组ID(PGID),假设在它的子进程中调用了exec()等系列函数,就不再能改变该子进程的进程组ID(PGID).
#include <unistd.h>
pid_t getsid(pid_t pid);
pid_t setsid(void);
函数说明:
会话是一个或多个进程组的集合.系统调用函数getsid()用来获取某个进程的会话ID(SID).
假设pid是0。返回调用进程的会话SID,一般说来。改制等于进程组ID(PGID).假设pid并不属于调用者所在的会话。则调用者就无法获取SID.
某个进程的会话ID也是能够改动的。调用函数setsid()用来创建一个新的会话.
假设调用进程已经是一个进程组的组长,则此函数返回错误.假设不是,则返回一个新的会话.
(1)该进程变成新会话首进程。会话首进程是创建该会话的进程。此时,该进程是新会话唯一的进程.
(2)该进程成为一个新的进程组的组长进程.新的进程组ID(PGID)是该调用进程的PID.
(3)该进程没有控制终端.假设在调用setsid()之前该进程就有一个控制终端,那么这样的联系也会中断.
#include <unistd.h>
pid_t tcgetpgrp(int fd);
int tcsetpgrp(int fd, pid_t pgrp);
函数说明:
会话和进程组的关系:
(1)一个会话能够有一个控制终端,建立于控制终端相连接的会话首进程被称为控制进程.
(2)一个会话中的几个进程组可被分为一个前台进程组和几个后台进程组,假设一个会话有一个控制终端,则他有一个前台进程组.
(3)不管何时键入终端的中断键,都会将中断信ID发送给前台进程组的全部会话。不管何时键入终端的退出键,都会将退出信ID发送给前台进程组的全部会话.
假设终端监測到调制解调器(或网络)已经断开连接,则将挂断信ID发送给控制进程(会话首进程).
调用函数tcgetgrpt()获取与打开的终端相关联的前台进程组的进程组ID.
调用函数tcsetgrpt()设置某个进程组是前台进程还是后台进程组.
假设进程有一个控制终端,则将前台进程组ID设置为pgrp,pgrp的值应该在同一会话中的一个进程组的ID。fd为控制终端的文件描写叙述符.
假设调用tcsetpgrp()函数的是会话中的后台进程组的进程,则该进程不会堵塞,或者忽略SIGTTOU信号.信号SIGTTOU将会发送给该进程组的全部进程.
当fd是指向进程的控制终端,函数tcgetpgrp()返回终端的前台进程组的进程组ID,该ID值是一个大于1且没有使用的值.假设fd指向的不是进程的终端,则函数返回-1,并设置errno指示出错.
图2 显示控制终端的进程组和会话
进程基本属性
1.进程ID(PID)
函数定义:#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
函数说明:
每一个进程都有一个非负整型表示的唯一进程ID(PID).好比方我们的身份证一样,每一个人的身份证号是唯一的.由于进程ID标示符总是唯一的,常将其用来做其它标示符的一部分以保证其唯一性。进程ID(PID)是无法在用户层改动的.
在Linux系统中,PID为0 的进程一般是调度进程。经常被称为交换进程,也是第一个系统进程.第一个用户进程是init进程。其PID为1.
在应用编程中。调用getpid()函数能够获得当前进程的PID,此函数没有參数,假设运行成功返回当前进程的PID。失败返回-1。出错原因存储于errno.
样例1:打印自己的进程ID(PID).
#include <unistd.h> #include <stdio.h> int main() { pid_t pid; //pid_t 事实上是int pid = getpid(); printf("the current program's pid is %d\n",pid); while(1); return 0; }
执行后使用“ps u”命令查看对比一下.
2.父进程ID(PPID)
函数定义:#include <sys/types.h>
#include <unistd.h>
pid_t getppid(void);
函数说明:
不论什么进程(除init进程)都是由还有一个进程创建。该进程称为被创建进程的父进程。被创建的进程称为子进程。父进程ID无法在用户层改动.父进程的进程ID即为子进程的父进程ID(PPID).
用户能够通过调用getppid()函数来获得当前进程的父进程ID(PPID).此函数没有參数,假设运行成功返回当前进程的父进程ID(PPID)。失败返回-1,出错原因存储于errno.
样例1:打印自己的父进程PPID.
#include <unistd.h> #include <stdio.h> int main() { pid_t ppid; //pid_t 事实上是int ppid = getppid(); printf("the current program's ppid is %d\n",ppid); while(1); return 0; }
执行后使用“ps u”命令查看对比一下.
3.进程组ID(process group ID PGID)
函数定义:#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);
pid_t getpgid(pid_t pid);
pid_t getpgrp(void); /* POSIX.1 version */
pid_t getpgrp(pid_t pid); /* BSD version */
int setpgrp(void); /* System V version */
int setpgrp(pid_t pid, pid_t pgid); /* BSD version */
函数说明:
在Linux系统中。每一个用户都实用户ID(UID)和用户组ID(GUID).相同,进程也拥有自己的进程ID(PID)和进程组ID(PGID). 进程组是一个或多个进程的集合;他们与同一作业相关联.每一个进程组都有唯一的进程组ID(PGID),进程组ID(PGID)能够在用户层改动.比方。将某个进程加入到还有一个进程组,就是使用setpgid()函数改动其进程组ID.
用户能够通过调用getpgid()函数来获得当前进程的进程组ID(PGID).若此參数为0表示获取当前进程的进程组ID,假设运行成功返回当前进程的进程组ID(PGID)。失败返回-1。出错原因存储于errno. 建议使用POSIX.1规定中的无參数getprgp()函数替代getpgid(pid)函数.
进程组ID(PGID)也能够通过函数getpgrp()获得.通过fork()函数产生的子进程会继承它的父进程的进程组ID(PGID).
每一个进程组都能够有一个组长进程,组长进程的进程组ID等于其进程ID.但组长进程能够先退出。即仅仅要在某个进程组中有一个进程存在,则该进程组就存在,与其组长进程是否存在无关.进程组的最后进程能够退出或转移到其它组.
能够将某个进程增加到某个进程组中,调用系统函数setpgid().其第一个參数为欲改动进程组ID(PGID)的进程ID(PID),第二參数为新的进程组ID(PGID),假设这两个參数相等,则由pid指定的进程变为该进程组组长。假设pid为0,则使用调用者的进程ID(即改动当前进程的进程组ID(PGID为指定的pgid));假设pgid是0,则由pid指定的进程ID(PID)。用做进程组ID(PGID)(即:pid所指进程作为进程组的组长进程).
一个进程仅仅能为自己或子进程设置进程组ID(PGID),假设在它的子进程中调用了exec()等系列函数,就不再能改变该子进程的进程组ID(PGID).
#include <unistd.h> #include <stdio.h> int main() { int i; printf("\t pid \tppid \t pgid\n"); printf("parent:\t%d\t%d\t%d\n",getpid(),getppid(),getpgid(0)); for(i=0; i<2; i++) { if(fork()==0) { printf("child:\t%d\t%d\t%d\n",getpid(),getppid(),getpgid(0)); } } sleep(500); return 0; }
输出:
4.会话(session)
函数定义:#include <unistd.h>
pid_t getsid(pid_t pid);
pid_t setsid(void);
函数说明:
会话是一个或多个进程组的集合.系统调用函数getsid()用来获取某个进程的会话ID(SID).
假设pid是0。返回调用进程的会话SID,一般说来。改制等于进程组ID(PGID).假设pid并不属于调用者所在的会话。则调用者就无法获取SID.
某个进程的会话ID也是能够改动的。调用函数setsid()用来创建一个新的会话.
假设调用进程已经是一个进程组的组长,则此函数返回错误.假设不是,则返回一个新的会话.
(1)该进程变成新会话首进程。会话首进程是创建该会话的进程。此时,该进程是新会话唯一的进程.
(2)该进程成为一个新的进程组的组长进程.新的进程组ID(PGID)是该调用进程的PID.
(3)该进程没有控制终端.假设在调用setsid()之前该进程就有一个控制终端,那么这样的联系也会中断.
图1 进程组合会话的进程安排
5.控制终端(controlling terminal)
函数定义:#include <unistd.h>
pid_t tcgetpgrp(int fd);
int tcsetpgrp(int fd, pid_t pgrp);
函数说明:
会话和进程组的关系:
(1)一个会话能够有一个控制终端,建立于控制终端相连接的会话首进程被称为控制进程.
(2)一个会话中的几个进程组可被分为一个前台进程组和几个后台进程组,假设一个会话有一个控制终端,则他有一个前台进程组.
(3)不管何时键入终端的中断键,都会将中断信ID发送给前台进程组的全部会话。不管何时键入终端的退出键,都会将退出信ID发送给前台进程组的全部会话.
假设终端监測到调制解调器(或网络)已经断开连接,则将挂断信ID发送给控制进程(会话首进程).
调用函数tcgetgrpt()获取与打开的终端相关联的前台进程组的进程组ID.
调用函数tcsetgrpt()设置某个进程组是前台进程还是后台进程组.
假设进程有一个控制终端,则将前台进程组ID设置为pgrp,pgrp的值应该在同一会话中的一个进程组的ID。fd为控制终端的文件描写叙述符.
假设调用tcsetpgrp()函数的是会话中的后台进程组的进程,则该进程不会堵塞,或者忽略SIGTTOU信号.信号SIGTTOU将会发送给该进程组的全部进程.
当fd是指向进程的控制终端,函数tcgetpgrp()返回终端的前台进程组的进程组ID,该ID值是一个大于1且没有使用的值.假设fd指向的不是进程的终端,则函数返回-1,并设置errno指示出错.
图2 显示控制终端的进程组和会话
笔者:个人能力有限,仅仅是学习參考...读者若发现文中错误,敬请提出.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙筑高台。静下心来,慢慢地沉淀---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------